【问题标题】:how to compare values between two files?如何比较两个文件之间的值?
【发布时间】:2019-06-19 05:39:52
【问题描述】:

我有两个文件,两列用空格隔开

cat file1.txt
281475225437349 33,32,21,17,20,22,18,30,19,16,23,31
281475550885480 35,32,33,21,39,40,57,36,41,17,20,38,34,37,16,99

cat file2.txt
281475550885480 16,17,20,21,32,33,34,35,36,37,38,39,40,41
281475225437349 16,17,18,19,20,21,22,23,24,25,30,31,32,33

我想比较 file1 column2 和 file2 column2 中的值,以获得 column1 中的相同值。 并只打印那些确实存在于file1 column2中但不存在于file2 column2中的值,反之亦然,以及column1中的相应值

所需的o/p

它不应该为 281475225437349 打印任何内容,因为 file1 列 2 中的所有值都存在于 281475225437349 的 file2 列 2 中

它应该只打印 281475550885480 的值,这些值存在于 file1 column2 但不存在于 file2 column2 中。 281475550885480 的类似值 57 和 99

所以像这样的o/p文件:

cat output.txt
281475550885480 57,99

我曾尝试使用 sdiff 对文件进行排序和比较,但它会产生差异并且需要时间

sdiff file1.txt file2.txt

【问题讨论】:

  • 我在您的帖子中添加了一些格式以便于理解。但那里似乎有一些重复。请您检查并删除所有重复的文本。
  • 欢迎来到 SO @Jeevan Patil,您的问题不清楚。请务必提及 3 个简单的事情,1- 输入样本,2- 输出样本和第 3- 任何您尝试在代码标签{} 按钮中修复它的内容,然后让我们知道。
  • 嗨。谢谢你的建议。我对其进行了编辑并删除了重复的语句

标签: perl sorting awk sed sdiff


【解决方案1】:

Perl 解决方案:从第二个文件创建一个哈希值。键是大数字,内部键是逗号分隔列表中的较小数字。然后遍历第一个文件并检查记忆结构中未提及的数字。

#!/usr/bin/perl
use warnings;
use strict;
use feature qw{ say };

open my $f1, '<', 'file1' or die $!;
open my $f2, '<', 'file2' or die $!;

my %seen;
while (<$f2>) {
    my ($key, $value_string) = split ' ';
    my @values = split /,/, $value_string;  #/
    undef @{ $seen{$key} }{@values};
}
while (<$f1>) {
    my ($key, $value_string) = split ' ';
    my @values = split /,/, $value_string;
    my %surplus;
    undef @surplus{@values};
    delete @surplus{ keys %{ $seen{$key} } };
    say $key, ' ', join ',', keys %surplus
        if keys %surplus;
}

顺便说一句,当你切换文件时,输出将是

281475225437349 24,25

因为 24 和 25 不在 file1 中。

【讨论】:

  • 您好,感谢您的意见。但是我的 perl 版本很旧,不支持 feature.pm。我不能升级perl。你能推荐一些替代品吗?
  • @JeevanPatil:只需使用print 而不是say 并附加"\n"
  • 太棒了.. 打印工作正常。谢谢 。但是我应该在哪一行添加“\n”?
  • print $key, ' ', (join ',', keys %surplus), "\n" if keys %surplus;
  • 哦,我明白了,要修复错误,请将if 条件添加到undef @{ $seen{$key} }{@values} if @values;
【解决方案2】:

您必须在代码中使用两个循环。在

之后还拆分 ',' 字符并设置两个数组
foreach(var itemOne as arrayOne){
boolean isExist=false;
foreach(var itemTwo as arrayTwo)
if(itemOne==itemTwo) isExist=true;

if(isExist) console.log(itemOne+" is exist");
}

【讨论】:

  • 看起来很像 C#。
【解决方案3】:

另一个awk

$ awk -v c=, 'NR==FNR {a[$1]=$2; next}
                      {for(i=2;i<=NF;i++) 
                         {if(c a[$1] c !~ c $i c) p=(p==""?$1" ":p c) $i} 
                          if(p) print p; p=""}' file2 FS=' |,' file1

281475550885480 57,99

【讨论】:

    【解决方案4】:

    使用 awk 很简单:

    awk '(NR==FNR) { a[$1]=","$2","; next }
         { delete b }                   # clear array for new run
         { split($2,f,",") }            # split string of file1 in array f
         { for(i in f) if (! match(a[$1],"," f[i] ",")) b[f[i]]  }                                                                                                                                                                             
         { c=$1" "; for(i in b) {printf c i; c="," }; if (c==",") printf "\n" }' file2 file1
    

    返回:

    281475550885480 57,99
    

    这个想法是用额外的两个存储第二列的字符串,以确保每个数字都在逗号之间。然后搜索逗号夹在中间的子字符串。

    如果您必须进行实数检查并且可能需要比较数字“5”和“005”并且它们应该相等,那么您应该执行以下操作:

    awk '(NR==FNR) { a[$1]=$2; next }
         { delete b }                       # clear array
         { # split strings in number elements
           split($2,f,",");    for(i in f) f1[f[i]+0];
           split(a[$1],f,","); for(i in f) f2[f[i]+0]
         }
         { for(i in f1) if (! (i in f2)) b[i] }
         { c=$1" "; for(i in b) {printf c i; c="," }; if (c==",") printf "\n" }' file2 file1
    

    【讨论】:

      【解决方案5】:

      这可能对你有用(GNU sed):

      sed -r 's#^(\S+)\s(\S+)$#/^\1 /s/$/,\\n\2,/#' file2 |
      sed -rnf - -e ':a;s/(\b[0-9]+,)(.*\n.*)\1/\2/;ta;s/(.*),\n.*/\1/p' file1
      

      解决方案可以分为两部分。

      第一个 file2 被转换为一个 sed 脚本,它将每个键的值附加到 file1 中的相同键。添加了额外的 , 以使匹配更容易,并将充当 file1 中的行是否具有要打印的值的指示符。

      从 file2 生成的脚本通过管道传输到第二次 sed 调用中,并且附加的下标使用替换和循环从 file1 中删除匹配值。

      如果匹配失败,并且由于第二次 sed 调用使​​用 -n 开关来显式打印,最终匹配会删除引入的 , 和换行后的不匹配值并打印所需的结果。

      【讨论】:

        【解决方案6】:
        $ cat tst.awk
        BEGIN { FS="[ ,]" }
        NR==FNR {
            for (i=2; i<=NF; i++) {
                file2[$1,$i]
            }
            next
        }
        {
            diff = ""
            for (i=2; i<=NF; i++) {
                if ( !(($1,$i) in file2) ) {
                    diff = (diff == "" ? "" : diff ",") $i
                }
            }
            if (diff != "") {
                print $1, diff
            }
        }
        
        $ awk -f tst.awk file2 file1
        281475550885480 57,99
        

        【讨论】: