比较两个数组并找出差异

4

我需要比较两个数组并获取它们之间的差异。

背景:

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

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

第一个数组的输出将是:

a
b
c
d
e

第二个数组的输出将是:
a
b
c
e

我如何比较这两个数组并找出它们之间的不同之处?我想要的最终输出是:
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;  

}
3个回答

5

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

为每个数组使用辅助哈希表,将存在性检查缩减为查找操作

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

这个函数可以找到两个数组之间的差异。如果你明确知道只需要找出第一个数组中有而第二个数组中没有的元素(从问题描述来看),那么可以调整子程序以仅返回所需内容。这样代码会更简洁,可以直接返回数组(列表或空数组)。

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

对于这种工作,有很好的模块可供使用。比较全面的模块是List::Compare。还有Array::UtilsArray::Compare等模块,也有更复杂的工具可用于此类工作,例如Algorithm::Diff


@daffodil 请描述一下为什么这对你不起作用,或者更新你的问题,这样人们就可以根据你的需求调整他们的答案。 - Grinnz
@daffodil 你说的“不工作”是指什么?我刚把这段代码复制粘贴到文件里运行了一遍,又进行了一次检查,它是可以正常工作的。请告诉我你的情况。 - zdim
顺便问一下,有办法让输出在新行中打印吗? - daffodil
@daffodil 很好,它能正常工作 :) 你说的“新行”是什么意思?一旦我们将其放入数组中,可以以任何方式打印它,你能解释一下(也许带个例子)你想要的是什么吗? - zdim
“在我上面的评论中,'与...相同'并不完全正确。使用“语句修饰符”(https://perldoc.perl.org/perlsyn.html#Statement-Modifiers)的“反转”的方法没有定义作用域,而且只能使用一个语句。” - zdim
显示剩余3条评论

4
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;
    }
}

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

另一种方法是,如果你只想找到在array2中不存在的array1元素,可以从第二个数组构建一个哈希表,并使用它来过滤第一个数组:

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

1
我会这样做:

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。 - daffodil
也许是因为数组没有共享任何元素?请展示您的代码。 - Skeeve

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接