2011-03-24 61 views
1

比方說,我有這些陣列如何比較2個數組並分成3組?

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

,我想他們相比,所以我得到含有不同

  • 與處於@new而不是元素的數組3個新的陣列@old:C
  • 與不是在@new的元素和在@old陣列:F
  • 與AR元素的數組E在兩個@new@old:A B dé

我思考exists功能,但只適用於哈希我想。

更新:我搞砸了字母的例子。

回答

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 
4

更新2:正如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, $_; 
+0

除了他希望交叉點*不是聯合。 – Axeman 2011-03-24 16:38:52

+0

@Axeman:是的。 '@ common'是路口。 – Dallaylaen 2011-03-24 17:57:09

+0

表示同意,但常見問題有'@ union'。我提高了您的解決方案 - 我認爲這是一個很好的解決方案,但評論說FAQ不會以相同的方式覆蓋*。 – Axeman 2011-03-24 18:49:27

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' 
     ]; 
2

一覽::比較處理這種類型的問題。

#!/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