【问题标题】:Perl - Filter function for arraysPerl - 数组的过滤函数
【发布时间】:2017-05-14 08:33:37
【问题描述】:

我正在尝试创建一个执行以下操作的子例程:

  1. 将两个数组作为输入(Filter、Base)
  2. 仅输出第二个数组中不存在于第一个数组中的值

例子:

@a = ( 1, 2, 3, 4, 5 );
@b = ( 1, 2, 3, 4, 5, 6, 7);

Expected output :   @c = ( 6, 7 );
Called as : filter_list(@filter, @base)

###############################################

sub filter_list {
    my @names = shift;
    my @arrayout;
    foreach my $element (@_)
    {
       if (!($element ~~ @names )){
       push @arrayout, $element;
    }
    }
   return @arrayout
}

试运行:

@filter = ( 'Tom', 'John' ); 
@array = ( 'Tom', 'John', 'Mary' );
@array3 = filter_list(@filter,@array);
print @array3;
print "\n";

结果:

JohnJohnMary

有人可以帮忙吗?谢谢。

【问题讨论】:

标签: arrays perl filter


【解决方案1】:

您不能将数组传递给 subs,只能传递标量。所以当你这样做时

my @filtered = filter_list(@filter, @base);

你真的在做

my @filtered = filter_list($filter[0], $filter[1], ..., $base[0], $base[1], ...);

因此,当你这样做时

my @names = shift;

你真的在做

my @names = $filter[0];

这显然是错误的。

最简单的解决方案是传递对数组的引用。

my @filtered = filter_list(\@filter, \@base);

哈希允许有效的实现 (O(N+M))。

sub filter_list {
   my ($filter, $base) = @_;
   my %filter = map { $_ => 1 } @$filter;
   return grep { !$filter{$_} } @$base;
}

或者,

my @filtered = filter_list(\@filter, @base);

可以实现为

sub filter_list {
   my $filter = shift;
   my %filter = map { $_ => 1 } @$filter;
   return grep { !$filter{$_} } @_;
}

【讨论】:

    【解决方案2】:

    您正在寻找的是两组的差异。这与 union、intersection 和其他一堆是 set operations。与其自己写,还有很多modules for dealing with sets

    Set::Object 非常快速且功能强大。我会避免使用操作员界面(即 $set1 - $set2),因为它会使代码混乱。而是使用显式方法调用。

    use strict;
    use warnings;
    use v5.10;
    
    use Set::Object qw(set);
    
    my $set1 = set(1, 2, 3, 4, 5);
    my $set2 = set(1, 2, 3, 4, 5, 6, 7);
    say join ", ", $set2->difference($set1)->members;
    

    请注意,集合是无序的,不能包含重复项。这可能是也可能不是您想要的。

    【讨论】:

      【解决方案3】:

      这使用了List::Compare,这是一个包含大量用于比较列表的例程集合的模块。

      你要get_complement

      use warnings;
      use strict;
      
      use List::Compare;
      
      my @arr1 = ( 1, 2, 3, 4, 5 );
      my @arr2 = ( 1, 2, 3, 4, 5, 6, 7);
      
      my $lc = List::Compare->new(\@arr1, \@arr2);
      
      my @only_in_second = $lc->get_complement;
      
      print "@only_in_second\n";
      

      该模块有很多选项。

      如果您不需要对结果进行排序,请将-u 传递给构造函数以加快操作。

      还有“加速模式”,通过-a获得。为了在相同数组之间进行有效的重复比较,许多东西在构造时预先计算。使用此标志被抑制,这加快了单一比较。见List::Compare Modes

      这两个选项可以组合,List::Compare->new('-u', '-a', \@a1, \@a2)

      支持对三个或更多列表的操作。

      还有功能接口,作为单独的List::Compare::Functional模块。

      【讨论】:

        猜你喜欢
        • 2023-03-20
        • 1970-01-01
        • 2016-12-29
        • 1970-01-01
        • 2020-02-24
        • 1970-01-01
        • 1970-01-01
        • 2021-12-12
        • 1970-01-01
        相关资源
        最近更新 更多