我有一个哈希列表,其中一些哈希包含一个自己提供数组的键。
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
。
有什么建议吗?
答案 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
: ()
;
}
对于减少决定是否“流式传输”数组和散列引用的长手方法来说,这是一个有用的习惯。