Поиск повторяющихся значений столбца в 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,

Это выведет что-то вроде «Повторяющийся идентификатор в строке 3».

Спасибо

PS этот файл CSV имеет больше столбцов и может содержать около 100 000 записей. Я упростил его по определенной причине, чтобы решить повторяющийся столбец/поле.

Спасибо


person sipher_z    schedule 17.01.2014    source источник
comment
вы вставляете в БД?   -  person user1844933    schedule 17.01.2014
comment
Как насчет того, чтобы помещать каждое значение в массив и проверять в каждой строке, что значение ID отсутствует в этом массиве? Тогда, если это так, просто echo "error on line xxx";   -  person Jerska    schedule 17.01.2014
comment
Если вы проверите это на сайте кодирования, это может привести к проблемам с производительностью. Я думаю, что лучше проверить уровень ввода данных и построить состояние CSV. Если вас не волнуют проблемы с производительностью, вы можете проверить, существует ли ваш идентификатор или нет в вашей базе данных или в хранилище на стороне программы.   -  person 502_Geek    schedule 17.01.2014


Ответы (3)


Я пошел, предполагая определенный тип дизайна, так как вырезал часть 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 секунды.)

РЕДАКТИРОВАТЬ: Как уже отмечалось, in_array менее эффективен, чем поиск по ключу. Следовательно, я обновил свой код.

person Jerska    schedule 17.01.2014

Попробуйте:

    $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);
    }
person dcapilla    schedule 17.01.2014

Отсортированы ли идентификаторы с возможными дубликатами между ними или они распределены случайным образом?

Если они отсортированы и в списке нет пробелов (1,2,3,4 — в порядке, 1,3,4,7 — НЕ в порядке), просто сохраните последний прочитанный идентификатор и сравните его с текущим идентификатором. Если текущий равен или меньше последнего, то это дубликат.

Если идентификаторы находятся в случайном порядке, вам придется хранить их в массиве. У вас есть несколько вариантов здесь. Если у вас много памяти, просто сохраните идентификатор как ключ в простом массиве PHP и проверьте его:

$ids = array();
// ... read and parse CSV
if (isset($ids[$newId])) {
    // you have a duplicate
} else {
    $ids[$newId] = true; // new value, not a duplicate
}

Массивы PHP представляют собой хеш-таблицы и имеют очень быстрый поиск ключей. Хранение идентификаторов в виде значений и поиск с помощью in_array() сильно снизят производительность по мере роста массива.

Если вам нужно сэкономить память и вы знаете количество строк, которые вы собираетесь прочитать из CSV, вы можете использовать SplFixedArray вместо простого массива PHP. Дубликат проверки будет таким же, как указано выше.

person ragol    schedule 17.01.2014
comment
Они распределены случайным образом. - person sipher_z; 17.01.2014