【问题标题】:Efficient way to find the differences in 2 csv files查找 2 个 csv 文件中差异的有效方法
【发布时间】:2016-10-23 12:08:17
【问题描述】:

我有 2 个大(比如 300,000 * 100)矩形 csv 文件,它们具有相同数量的相应行和列。我需要找出 2 个文件中每个对应单元格之间的差异(如果有的话)。 程序应该o/p不同的行号和单元格号以及不同的内容。

由于行/列的数量非常大,我正在寻找最有效的方法。

最初我开始使用 awk 进行探索,this 看起来很有希望,但我之前没有使用过 awk 并且未能成功地将其扩展到 100 列而不是示例中的 2 列

接下来,我尝试了一种使用 Java 的蛮力方法 - 将文件加载到 2 个二维数组中。初始化 100 个线程,每个线程处理给定的列,当发现差异时,每个线程将行、单元格和差异值放入 HashMap(以列号为 Key)。我确实尝试通过在将第二个文件读入数组时进行比较来优化它,但实际上因为我正在访问每个单元格,所以它不可能很快(花了将近 8 个小时来完成比较)

我可以使用 awk 或 Java。并对任何其他完全不同的方法持开放态度。

【问题讨论】:

  • 只使用diff 来检查文件中的差异怎么样?输出可以存储在文件中或在脚本中使用以进一步分析并采取适当的措施。
  • 这正是当前程序正在做的事情。 diff 只打印整行,在许多情况下,从左侧文件中打印 10 行,然后在右侧文件中打印 10 行。因此,必须手动复制到 excel 中并在视觉上比较每一列。请注意,90% 的行有一些差异。所以差异 o/p 非常大
  • 那么让excel来整理呢?没有完全跟上它的功能,但我相信一些矩阵搜索可以应用于多个选项卡并可能更改背景颜色?
  • 需要一些信息:您预计线路平均有多少差异?另外,数据类型是什么?混合(文本/日期/数字)还是仅数字?
  • 每行介于 1 - 10 之间。数据好坏参半。在 80% 的情况下,如果某一列的行中出现差异,则大多数行中都会出现相同的情况。所以我现在正在考虑进行选择性比较(也许一些逻辑只遍历部分行,修复导致差异的问题并重新运行,这将导致它比较其他行)尚不清楚,但这些行上的东西会乐于助人

标签: java csv awk


【解决方案1】:

awk 来救援!

awk 中这样做很容易

$ paste -d, file.1 file.2 | 
  awk -F, '{m=NF/2; for(i=1;i<=m;i++) if($i!=$(i+m)) print NR,i,$i,$(i+m)}'

打印不相等单元格的“row# column# left right”值。

如果你想打印除行号之外的关键列,可以轻松添加

$ paste -d, file.1 file.2 | 
  awk -F, -v key=8 '{m=NF/2; 
                     for(i=1;i<=m;i++) 
                       if($i!=$(i+m)) print $key,NR,i,$i,$(i+m)}'

【讨论】:

  • 是否可以在输出中 o/p 固定列的值(例如第 8 列的值)?此特定值保证与行的唯一键相同
  • 如果你用你的文件尝试这个,请发布时间,它不应该超过一分钟左右。
  • 太棒了.. 大约需要 1.5 分钟才能完成。 Java 版本当然有额外的输出,但由于速度慢而无用。会接受这个答案。我应该能够进一步使用 o/p 来获得我需要的东西。谢谢
【解决方案2】:

需要考虑的事项:

$ cat file1
1,2,aa
1,2,3
1,bb,3
1,2,3

$ cat file2
1,2,cc
1,2,3
1,dd,3
1,2,3

$ diff file1 file2 |
awk -F, '
    /^[0-9]/ { row=$0+0; next }
    sub(/^< /,"") { split($0,a); next }
    sub(/^> /,"") { for (col=1;col<=NF;col++) if ($col != a[col]) print row, col, a[col], $col }
'
1 3 aa cc
3 2 bb dd

这应该非常快,因为它只执行 awk 并在有差异的行上循环,而不是所有行。

【讨论】:

    【解决方案3】:

    univocity-parsers' CSV 解析器处理这个的时间不会超过 5 秒:

    public void diff(File leftInput, File rightInput) {
        CsvParserSettings settings = new CsvParserSettings(); //many config options here, check the tutorial
    
        CsvParser leftParser = new CsvParser(settings);
        CsvParser rightParser = new CsvParser(settings);
    
        leftParser.beginParsing(leftInput);
        rightParser.beginParsing(rightInput);
    
        String[] left;
        String[] right;
    
        int row = 0;
        while ((left = leftParser.parseNext()) != null && (right = rightParser.parseNext()) != null) {
            row++;
            if (!Arrays.equals(left, right)) {
                System.out.println(row + ":\t" + Arrays.toString(left) + " != " + Arrays.toString(right));
            }
        }
    
        leftParser.stopParsing();
        rightParser.stopParsing();
    }
    

    披露:我是这个库的作者。它是开源免费的(Apache V2.0 许可)。

    【讨论】:

      猜你喜欢
      • 2015-08-22
      • 2021-10-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-01-05
      • 2016-07-13
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多