缩短代码:从哈希合并数组

时间:2011-09-21 10:47:08

标签: perl refactoring perl-data-structures perl-hash

我有一个哈希列表,其中一些哈希包含一个自己提供数组的键。

my @cars = (
   { # empty car
      name => "BMW",
   },
   { # car with passengers
      name => "Mercedes",
      passengers => [qw(Paul Willy)],
   },
   ...
)

这几乎就像上面一样,但当然不是以愚蠢的汽车为例: - )

现在我需要从所有哈希中获得所有“乘客”的列表,包括那些甚至不提供乘客阵列的乘客。

在第二步中,我需要从列表中检索唯一条目(实际上乘客是Perl对象引用,我需要列表中的每个对象一次)

目前我这样做:

my (@all, @passengers, %seen);
for(@cars) {
    push @all, @{$_->{passengers}} if $_->{passengers};
}

@passengers = grep { ! $seen{$_} ++ } @all;

我想摆脱@all并将所有乘客的名单直接扔到grep

有什么建议吗?

3 个答案:

答案 0 :(得分:6)

my %seen;
my @passengers = grep { ! $seen{$_} ++ }
                 map { @{$_->{passengers} || []} } @cars;

答案 1 :(得分:2)

这让我觉得创建一个数组和一个引用只是为了立即摆脱它(就像cjm那样),所以我用

my %seen;
my @passengers =
   grep !$seen{$_}++,
   map $_ ? @$_ : (),
   map $_->{passengers},
   @cars;

my %seen;
my @passengers =
   grep !$seen{$_}++,
   map @{ $_->{passengers} },
   grep $_->{passengers},
   @cars;

答案 2 :(得分:1)

这是另一种变化。它使用List::MoreUtils::uniq%seen这些东西很有用,但这些日子是不必要的。

use List::MoreUtils qw<uniq>;

my @passengers 
    = sort uniq map { @$_ } grep { defined } map { $_->{passengers} } @cars
    ;

当然,使用我list_if的成语,我会这样做:

 my @passengers = sort uniq map { list_if( $_->{passengers} ) } @cars;

list_if定义为:

sub list_if {
    use Params::Util qw<_ARRAY _HASH>;

    return unless my $cond = shift;
    return unless my $ref
        = @_ == 0 ? $cond
        : @_ == 1 ? $_[0]
        :          \@_
        ;
    return !ref( $ref )   ? $ref
         : _ARRAY( $ref ) ? @$ref
         : _HASH( $ref )  ? %$ref
         :                  ()
         ;              
}

对于减少决定是否“流式传输”数组和散列引用的长手方法来说,这是一个有用的习惯。