Reputation: 37440
It seems like I should be able to do this with map, but the actual details elude me.
I have a list of strings in an array, and either zero or one of them may have a hash value.
So instead of doing:
foreach $str ( @strings ) {
$val = $hash{$str} if $hash{$str};
}
Can this be replaced with a one-liner using map?
Upvotes: 1
Views: 1921
Reputation: 110429
Sure, it'd be:
map { $val = $hash{$_} } @strings;
That is, each value of @strings
is set in $_
in turn (instead of $str
as in your foreach).
Of course, this doesn't do much, since you're not doing anything with the value of $val
in your loop, and we aren't capturing the list returned by map
.
If you're just trying to generate a list of values, that'd be:
@values = map { $hash{$_} } @strings;
But it's more concise to use a hash slice:
@values = @hash{@strings};
EDIT: As pointed out in the comments, if it's possible that @strings
contains values that aren't keys in your hash, then @values
will get undefs in those positions. If that's not what you want, see Hynek's answer for a solution.
Upvotes: 4
Reputation: 26121
I'm used to do it in this way:
@values = map { exists $hash{$_} ? $hash{$_} : () } @strings;
but I don't see anything wrong in this way
push @values, $hash{$_} for grep exists $hash{$_}, @strings;
or
@values = @hash{grep exists $hash{$_}, @strings};
Upvotes: 3
Reputation: 118118
@values = grep { $_ } @hash{@strings};
to account for the fact that you only want true values.
Change this to
@values = grep { defined } @hash{@strings};
if you want to skip undefined values.
Upvotes: 6