如何比较2个阵列并分成3组?

时间:2011-03-24 15:19:59

标签: arrays perl

假设我有这些数组

my @new = qw/a b c d e/;
my @old = qw/a b   d e f/;

我希望他们进行比较,所以我得到3个包含差异的新数组

  • 包含@new但不在@old中的元素的数组:c
  • 包含不在@new@old中的元素的数组:f
  • 包含@new@old中元素的数组:a b d e

我正在考虑exists函数,但这只适用于我想要的哈希值。

更新:我搞砸了信件的例子。

6 个答案:

答案 0 :(得分:4)

答案 1 :(得分:4)

UPDATE2:正如Michael Carman指出的那样,如果元素重复,我的算法将失败。因此,固定解决方案使用一个哈希:

my (%count, %old);
$count{$_} = 1 for @new;
$old{$_}++ or $count{$_}-- for @old;
# %count is now really like diff(1)    

my (@minus, @plus, @intersection);
foreach (keys %count) {
    push @minus, $_        if $count{$_}  < 0;
    push @plus, $_         if $count{$_}  > 0;
    push @intersection, $_ if $count{$_} == 0;
};

更新:看起来此解决方案还涵盖了常见问题解答中的内容:

    push @difference, $_ if $count{$_};
    push @union, $_;

答案 2 :(得分:3)

这是我多次使用的功能。

sub compute_sets {
    my ($ra, $rb) = @_;
    my (@a, @b, @ab, %a, %b, %seen);

    @a{@$ra} = ();
    @b{@$rb} = ();

    foreach (keys %a, keys %b) {
        next if $seen{$_}++;

        if (exists $a{$_} && exists $b{$_}) {
            push(@ab, $_);
        }
        elsif (exists $a{$_}) {
            push(@a, $_);
        }
        else {
            push(@b, $_);
        }
    }

    return(\@a, \@b, \@ab);
}

它返回对包含第一个/第二个/两个列表中元素的数组的引用:

my @new = qw/a b c d e/;
my @old = qw/a b   d e f/;

my ($new_only, $old_only, $both) = compute_sets(\@new, \@old);

say 'new only: ', join ' ', @$new_only; # c
say 'old only: ', join ' ', @$old_only; # f
say 'both: ', join ' ', @$both;         # e a b d

答案 3 :(得分:2)

答案 4 :(得分:2)

List :: Compare处理这类问题。

#!/usr/bin/perl
use strict;
use warnings;
use List::Compare;

my @new = qw/a b c d e/;
my @old = qw/a b   d e f/;

my $lc = List::Compare->new(\@new, \@old);

# an array with the elements that are in @new and not in @old : c
my @Lonly = $lc->get_Lonly;
print "\@Lonly: @Lonly\n";

# an array with the elements that are not in @new and in @old : f
my @Ronly = $lc->get_Ronly;
print "\@Ronly: @Ronly\n";

# an array with the elements that are in both @new and @old : a b d e
my @intersection = $lc->get_intersection;
print "\@intersection: @intersection\n";

__END__
** prints

@Lonly: c
@Ronly: f
@intersection: a b d e

答案 5 :(得分:1)

怎么样:

#!/usr/bin/perl
use strict;
use warnings;
use Data::Dumper;

my @new = qw/a b c d e/;
my @old = qw/a b   d e f/;
my %new = map{$_ => 1} @new;
my %old = map{$_ => 1} @old;

my (@new_not_old, @old_not_new, @new_and_old);
foreach my $key(@new) {
    if (exists $old{$key}) {
        push @new_and_old, $key;
    } else {
        push @new_not_old, $key;
    }
}
foreach my $key(@old) {
    if (!exists $new{$key}) {
        push @old_not_new, $key;
    }
}

print Dumper\@new_and_old;
print Dumper\@new_not_old;
print Dumper\@old_not_new;

<强>输出:

$VAR1 = [
          'a',
          'b',
          'd',
          'e'
        ];
$VAR1 = [
          'c'
        ];
$VAR1 = [
          'f'
        ];