如何从数组中减去数组?

时间:2011-02-03 21:23:26

标签: arrays perl

当我尝试以下

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

这里有什么问题?

7 个答案:

答案 0 :(得分:34)

您需要将@bl转换为哈希来执行设置差异:

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

答案 1 :(得分:4)

请参阅perlfaq4: How do I compute the difference of two arrays?

在您的代码中,not可能没有按照您的想法进行操作。

如果not @bl为空数组,则{p> 1始终为@bl;如果undef不为空,则@bl将为@bl。 它并不意味着“任何意义上都不在{{1}}中的元素”。

答案 2 :(得分:4)

@b1求值为true(它是一个元素数量非零的数组),因此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];

答案 3 :(得分:4)

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

使用Smartmatch-operator的另一种方法(如果你有perl-version 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

答案 4 :(得分: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;

答案 5 :(得分:1)

另一种方法,使用Acme::Tools CPAN模块中的minus函数:

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

答案 6 :(得分:-1)

另一种方法是使用:

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