Поиск повторяющихся значений столбцов в CSV
Я импортирую CSV, который имеет 3 столбца, один из этих столбцов может содержать дубликаты записей.
Мне нужно проверить 2 вещи:
1. The field 'NAME' is not null and is a string
2. The field 'ID' is unique
До сих пор я анализирую CSV-файл, один раз и проверяю, что 1. (NAME is valid), который, если он не работает, просто вырывается из цикла while и останавливается.
Наверное, вопрос в том, как я проверю, что ID уникален?
У меня есть поля, подобные следующим:
NAME, ID,
Bob, 1,
Tom, 2,
James, 1,
Terry, 3,
Joe, 4,
Это выведет что-то вроде ' дубликат ID в строке 3'
Спасибо
P. S этот CSV-файл содержит больше столбцов и может содержать около 100 000 записей. Я упростил его по определенной причине, чтобы решить дубликат столбца / поля
Спасибо
4 ответов:
Я пошел предполагая определенный тип дизайна, так как убрал CSV часть, но идея останется прежней:
<?php /* Let's make an array of 100,000 rows (Be careful, you might run into memory issues with this, issues you won't have with a CSV read line by line)*/ $arr = []; for ($i = 0; $i < 100000; $i++) $arr[] = [rand(0, 1000000), 'Hey']; /* Now let's have fun */ $ids = []; foreach ($arr as $line => $couple) { if ($ids[$couple[0]]) echo "Id " . $couple[0] . " on line " . $line . " already used<br />"; else $ids[$couple[0]] = true; } ?>100 000 строк-это не так уж много, этого будет достаточно. (Он бежал в течение 3 секунд у меня дома.)
EDIT: как уже отмечалось,
in_arrayменее эффективен, чем поиск ключей. Поэтому я обновил свой код.
<?php $cnt = 0; $arr=array(); if (($handle = fopen("1.csv", "r")) !== FALSE) { while (($data = fgetcsv($handle, 1000, ",")) !== FALSE) { $num=count($data); $cnt++; for ($c=0; $c < $num; $c++) { if(is_numeric($data[$c])){ if (array_key_exists($data[$c], $arr)) $arrdup[] = "duplicate value at ".($cnt-1); else $arr[$data[$c]] = $data[$c-1]; } } } fclose($handle); } print_r($arrdup);
Попробуйте:
$row = 1; $totalIDs = array(); if (($handle = fopen('/tmp/test1.csv', "r")) !== FALSE) { while (($data = fgetcsv($handle, 1000, ",")) !== FALSE) { $name = ''; if (isset($data[0]) && $data[0] != '') { $name = $data[0]; if (is_numeric($data[0]) || !is_string($data[0])) echo "Name is not a string for row $row\n"; } else { echo "Name not set for row $row\n"; } $id = ''; if (isset($data[1])) { $id = $data[1]; } else { echo "ID not set for row $row\n"; } if (isset($totalIDs[$id])) echo "Duplicate ID on line $row\n"; else $totalIDs[$id] = 1; $row++; } fclose($handle); }
Сортируются ли идентификаторы с возможными дубликатами между ними или они распределены случайным образом?
Если они отсортированы и в списке нет дырок (1,2,3,4 в порядке; 1,3,4,7 не в порядке), то просто сохраните последний прочитанный идентификатор и сравните его с текущим идентификатором. Если текущий равен или меньше последнего, то это дубликат.
Если идентификаторы расположены в случайном порядке, то вам придется хранить их в массиве. У вас есть несколько вариантов здесь. Если у вас много памяти, просто сохраните идентификатор как ключ в простом массиве PHP и проверьте его:
Массивы PHP являются хэш-таблицами и имеют очень быстрый поиск ключей. Хранение идентификаторов в виде значений и поиск с помощью$ids = array(); // ... read and parse CSV if (isset($ids[$newId])) { // you have a duplicate } else { $ids[$newId] = true; // new value, not a duplicate }in_array()сильно повредит производительности по мере роста массива.Если вам нужно сохранить память и вы знаете количество строк, которые вы собираетесь прочитать из CSV, вы можете использовать
SplFixedArrayвместо простого массива PHP. Дубликат чека будет таким же, как и выше.
Comments