0

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

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.

有什么建议么?

4

3 回答 3

6
my %seen;
my @passengers = grep { ! $seen{$_} ++ }
                 map { @{$_->{passengers} || []} } @cars;
于 2011-09-21T10:57:39.153 回答
2

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

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

或者

my %seen;
my @passengers =
   grep !$seen{$_}++,
   map @{ $_->{passengers} },
   grep $_->{passengers},
   @cars;
于 2011-09-21T15:57:10.753 回答
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
         :                  ()
         ;              
}

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

于 2011-09-21T17:35:15.620 回答