【问题标题】:Finding duplicate column values in a CSV在 CSV 中查找重复的列值
【发布时间】:2014-01-17 10:50:52
【问题描述】:

我正在导入一个包含 3 列的 CSV,其中一列可能有重复记录。

我有两件事要检查:

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 行重复 ID”的内容

谢谢

P.S 这个 CSV 文件有更多的列,可以有大约 100,000 条记录。我出于特定原因对其进行了简化以解决重复的列/字段

谢谢

【问题讨论】:

  • 你要插入数据库吗?
  • 如何将每个值推入数组并检查每一行 ID 值是否不在此数组中?如果是的话,就echo "error on line xxx";
  • 如果您在编码站点检查此内容,则可能会出现性能问题。我认为,更好的方法是检查数据输入级别并构建 CSV 状态。如果不关心性能问题,您可以在程序端检查您的 ID 是否已存在于您的数据库或存储位置。

标签: php csv fgetcsv


【解决方案1】:
<?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);

【讨论】:

    【解决方案2】:

    试一试:

        $row = 1;
        $totalIDs = array();
        if (($handle = fopen('/tmp/test1.csv', "r")) !== FALSE) 
        {
            while (($data = fgetcsv($handle)) !== 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);
        }
    

    【讨论】:

      【解决方案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 的效率低于键查找。因此,我更新了我的代码。

      【讨论】:

        【解决方案4】:

        ID 是按可能重复的方式排序的,还是随机分布的?

        如果它们已排序并且列表中没有空洞(1,2,3,4 可以;1,3,4,7 不可以),则只需存储您读取的最后一个 ID 并将其与当前标识。如果 current 等于或小于 last 则它是重复的。

        如果 ID 是随机顺序的,那么您必须将它们存储在一个数组中。您在这里有多种选择。如果您有足够的内存,只需将 ID 作为键存储在普通 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 数组是哈希表,并且具有非常快速的键查找。随着数组的增长,将 ID 存储为值并使用 in_array() 进行搜索会大大降低性能。

        如果您必须节省内存并且知道要从 CSV 读取的行数,则可以使用 SplFixedArray 而不是普通的 PHP 数组。重复检查将与上述相同。

        【讨论】:

        • 它们是随机分布的。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2020-09-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-01-22
        • 1970-01-01
        • 2019-11-10
        相关资源
        最近更新 更多