I have a list of hashes and some of the hashes contain a key which provides an array itself.
my @cars = (
{ # empty car
name => "BMW",
},
{ # car with passengers
name => "Mercedes",
passengers => [qw(Paul Willy)],
},
...
)
It's pretty much like above but of course not with the stupid cars example:-)
Now I need to get a list of all "passengers" from all hashes including ones that do not even offer a passengers array.
In a 2nd step I need to retrieve unique entries from the list (actually the passengers are Perl object refs and I need every object once in the list)
At the moment I do:
my (@all, @passengers, %seen);
for(@cars) {
push @all, @{$_->{passengers}} if $_->{passengers};
}
@passengers = grep { ! $seen{$_} ++ } @all;
I would like to get rid of @all and throw the list of all passengers directly into grep
.
Any suggestions?
Here's another variation. It uses List::MoreUtils::uniq
. The %seen
stuff is good to know, but unnecessary these days.
use List::MoreUtils qw<uniq>;
my @passengers
= sort uniq map { @$_ } grep { defined } map { $_->{passengers} } @cars
;
Of course, using my idiom of list_if
, I would just do this:
my @passengers = sort uniq map { list_if( $_->{passengers} ) } @cars;
Where list_if
is defined as:
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
: ()
;
}
It's been a useful idiom for cutting down on long-hand approaches to deciding whether to "stream" array and hash refs or not.