【问题标题】:Comparing two arrays and finding differences比较两个数组并找出差异
【发布时间】:2019-06-12 06:28:54
【问题描述】:

我需要比较两个数组并获得差异。

背景:

第一个数组将列出文件夹中的文件。

第二个数组将读取文件的内容并存储在数组中。

第一个数组的输出将是

a
b
c
d
e

第二个数组的输出将是

a
b
c
e

我如何比较那些有差异的 2 个数组?我想要的结局输出是

d

代码如下:

#!/usr/bin/perl

use strict;
use warnings;

my $list  = "experiment.sv";
my $path  = "../../../folder1/";
my $filelist;

open ( OUTFILE, ">output.txt" );
main ();
close OUTFILE;


sub main {

   my @array1;
   opendir ( DIR, $path ) || die "Error in opening dir $path\n"; 
   while ( $filelist = readdir (DIR) ) {
       next if ( $filelist =~ s/\.//g);   #/
       push @array1, $filelist;         
   }
   closedir(DIR);

   my @array2;
   open( my $fh, "<", "$path/$list") or die "Failed to open file: $!\n";   
   while(<$fh>) { 
      push @array2, $_;                  
   } 
   close $fh;

   my @result;
   foreach my $array2 (@array2) {
       foreach my $array1 (@array1) {
           if ($array1 !~ /$array2/ ) {
               push @result, "$array1\n";
           }
       }
   }

   print OUTFILE "",@result;  

}

【问题讨论】:

    标签: arrays algorithm perl comparison


    【解决方案1】:

    有几种方法可以做到这一点,也取决于具体需要什么。

    对每个数组使用辅助散列,将存在性检查减少为查找

    use warnings;
    use strict;
    use feature 'say';
    
    sub diff_arys {
        my ($ra1, $ra2) = @_;
    
        my %in_a1 = map { $_ => 1 } @$ra1;
        my %in_a2 = map { $_ => 1 } @$ra2;
    
        my @not_in_one = grep { not exists $in_a1{$_} } @$ra2;
        my @not_in_two = grep { not exists $in_a2{$_} } @$ra1;
    
        return (@not_in_one ? \@not_in_one : undef), 
               (@not_in_two ? \@not_in_two : undef);
    }
    
    my @ary1 = 'a'..'e';         # a,b,c,d,e
    my @ary2 = ('a'..'d', 'z');  # a,b,c,d, z
        
    my ($not_in_one, $not_in_two) = diff_arys(\@ary1, \@ary2);
    
    say "@$not_in_one"  if $not_in_one;
    say "@$not_in_two"  if $not_in_two;
    

    打印

    z e

    这发现了两种方式的差异,一个数组中的元素而不是另一个数组中的元素。如果您确实知道您只需要一个“方向”来识别第一个数组中而不是第二个数组中的东西(从问题看来),然后调整 sub 以便只获得所需的返回。然后代码更少,你可以只返回数组(所以,一个列表或空)

    注意接口的选择:如果没有发现差异,则返回undef,否则返回arrayref。

    这类工作有很好的模块。比较全面的一个是List::Compare。还有Array::UtilsArray::Compare,等等。然后还有更复杂的工具也可以用于此目的,例如 Algorithm::Diff

    【讨论】:

    • @daffodil 请描述为什么它不适合您,并可能更新您的问题,以便人们可以根据您的需要调整他们的答案。
    • @daffodil 怎么样 - 什么“不起作用”?我只是将它复制粘贴到一个文件中并运行它,以进行另一次检查,它可以工作。请让我知道它对您有什么作用。
    • 嗨,它已经工作了,这是由于我的前两个数组编码错误。非常感谢!
    • 顺便说一句,输出是否可以换行打印?
    • @daffodil 很好用 :) “换行”是什么意思?一旦我们将它放在数组中,就可以以任何方式打印它,你能解释一下(可能有一个例子吗?)你想要它吗?
    【解决方案2】:

    perldoc -q "difference of" 中所述,您可以像这样得到两个数组的对称差:

    my %count;
    for my $x (@array1, @array2) {
        $count{$x}++;
    }
    my @difference;
    for my $x (keys %count) {
        if ($count{$x} == 1) {
            push @difference, $x;
        }
    }
    

    这假设两个数组中都没有重复元素。

    或者,如果您只想查找 array1 中不存在于 array2 中的元素,您可以从第二个数组构建一个哈希并使用它来过滤第一个数组:

    my %seen;
    $seen{$_} = 1 for @array2;
    my @missing = grep !$seen{$_}, @array1;
    

    【讨论】:

      【解决方案3】:

      我会这样做:

      use Data::Dumper;
      my @array1= (qw(a b c d e f g   i  ));
      my @array2= (qw(a b c   e   g h i j));
      
      my %missing1, %missing2;
      
      # Create an hash entry (value undef) for every array1 member
      @missing1{@array1} = ();
      # Delete every array2 member
      delete @missing1{@array2};
      
      # and v.v.
      @missing2{@array2} = ();
      delete @missing2{@array1};
      
      print "Elements of array 1 missing in array 2:\n", Dumper sort keys %missing1;
      print "Elements of array 2 missing in array 1:\n", Dumper sort keys %missing2;
      

      【讨论】:

      • 感谢您的建议,这对我不起作用,因为它们都只是打印出数组 1 和数组 2
      • 也许这是因为数组不共享任何元素?显示您的代码。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-12-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-07-19
      • 1970-01-01
      相关资源
      最近更新 更多