2011-02-03 159 views
16

当我尝试以下方法如何从数组中减去数组?

#!/usr/bin/perl 

use strict; 
use warnings; 
use Data::Dumper; 

my @bl = qw(red green blue); 
my @a = qw(green yellow purple blue pink); 

print Dumper [grep {not @bl} @a]; 

我得到一个空数组。我预料@bl@a减去,所以输出是yellow purple pink

这里有什么问题?

+2

“减”是不正确的字在这里。当你**找到正确的单词时,你会发现它是一个触发巴洛克式散列攻击的单词。 – tchrist 2011-02-04 01:15:41

回答

33

您需要打开@bl到一个哈希执行差集:

my %in_bl = map {$_ => 1} @bl; 
my @diff = grep {not $in_bl{$_}} @a; 
+7

这比这个问题的常见问题回答更好 - 常见问题解答仅向您展示如何计算两个数组之间的“对称差异” – mob 2011-02-03 21:35:33

+1

@mob:因此,邮件布莱恩与建议的更新。 – tchrist 2011-02-04 01:16:44

+6

在Perl 5.10或更新的版本中,您可以将其编写为`my @diff = grep {not $ _ ~~ @bl} @a;` – 2011-03-28 14:46:34

4

@b1计算结果为真(这是一个非零数字元素的数组),因此布尔测试你的grep构造(not @b1)将始终返回false。 grep过滤仅返回布尔测试返回true的元素的数组。

您需要测试以确定$_(当前正在考虑的数组元素)是否在@bl之内。要做到这一点的方法之一是使用@bl作为键,然后在grep的声明支票的$_在哈希键的存在,产生一个临时散:

#!/usr/bin/perl 

use strict; 
use warnings; 
use Data::Dumper; 

my @bl = qw(red green blue); 
my @a = qw(green yellow purple blue pink); 

# create a hash 
my %h; 

# nifty trick - use a hash slice to populate the 
# hash. The values are irrelevant so we'll use @bl 
# for those too 
@h{@bl} = @bl; 

print Dumper [grep {!exists $h{$_}} @a]; 
1

的另一种方法,使用minus功能从Acme::Tools CPAN模块:

use strict; 
use warnings; 
use Data::Dumper; 
use Acme::Tools qw(minus); 

my @bl = qw(red green blue); 
my @a = qw(green yellow purple blue pink); 
my @diff = minus(\@a, \@bl); 
print Dumper(\@diff); 

__END__ 

$VAR1 = [ 
      'yellow', 
      'purple', 
      'pink' 
     ]; 
2

另一种选择使用perl5i

use perl5i::2; 

my @bl = qw(red green blue); 
my @a = qw(green yellow purple blue pink); 
my @diff = @a->diff(\@bl); 

say @diff->mo->perl; 
4

由于Perl 5.18.0,smartmatch运算符被认为是实验性的: The smartmatch family of features are now experimental。 因此,我不会再使用下面的解决方案。

与Smartmatch运营商的另一种方式(如果你有Perl版本5.010或更高):

#!/usr/bin/env perl 
use warnings; 
use 5.012; 

my @bl = qw(red green blue); 
my @a = qw(green yellow purple blue pink); 

my @s = grep{ not $_ ~~ @bl } @a; 
say "@s"; # yellow purple pink 
-1

另一种方法是使用:

List::Compare CPAN module 
use List::Compare ; 
... 
my $compare_obj 
    = List::Compare->new(\@a , \@b1) ; 
@diff = $compare_obj->get_Lonly() ; 
...