【问题标题】:How to subtract an array from an array?如何从数组中减去数组?
【发布时间】:2011-06-20 23:38:08
【问题描述】:

当我尝试以下操作时

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

我得到一个空数组。我本来希望从@a 中减去@bl,所以输出是yellow purple pink

这里有什么问题?

【问题讨论】:

  • “减法”在这里不是正确的词。当您确实找到正确的词时,您会发现它会触发巴甫洛夫哈希攻击。

标签: arrays perl


【解决方案1】:

需要将@bl转成hash来执行集差:

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

【讨论】:

  • 这比这个问题的常见问题解答要好——常见问题解答只向您展示如何计算两个数组之间的“对称差”
  • 在 Perl 5.10 或更高版本中,您可以编写它my @diff = grep{ not $_ ~~ @bl } @a;
  • @BradGilbert 和 6 年后,您会收到警告说这是一个实验性功能。这种比较在未来可能会改变。
  • @BradGilbert 文档声明智能匹配将匹配$_@bl 中的每个元素。这个答案只需要遍历@bl 一次即可进行哈希,因此性能上有显着差异。 perldoc.perl.org/perlop.html#Smartmatch-Operator
【解决方案2】:

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

在您的代码中,not 可能没有做您认为它正在做的事情。

如果@bl 是空数组,not @bl 将始终为1,如果@bl 不为空,则undef。 这并不意味着任何意义上的“不在@bl 中的元素”。

【讨论】:

    【解决方案3】:

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

    【讨论】:

    • 填充%h 的值是多余的。如果您使用exists,则使用@h{@bl}=() 填充会很好,而且可能更快。
    【解决方案4】:

    自 Perl 5.18.0 以来,智能匹配运算符被认为是实验性的: 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
    

    【讨论】:

    • 这不会导致O(n^2) 的性能,因为对于@a 中的每个元素,智能匹配运算符会匹配@bl 的每个元素?
    • @Floegipoky:你的评论对我来说听起来很合理。在 Perl 5 中,我停止使用 smartmatch 运算符。我已经编辑了答案。
    【解决方案5】:

    另一个使用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;
    

    【讨论】:

      【解决方案6】:

      另一种方式,使用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'
              ];
      

      【讨论】:

        【解决方案7】:

        另一种方法是使用:

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-03-09
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多