Can I avoid referencing + dereferencing the hash returned from a map operation?
I've got an array of hashes. I want the a list of the values in a key of those hash开发者_Python百科es based on the uniqueness of another key.
my @obs = ({
value => 'three',
id => 3
},{
value => 'one-2',
id => 1
},{
value => 'one',
id => 1
});
# This works, prints "one\nthree"
say for values %{{ map { $_->{id} => $_->{value} } @obs }};
Can I avoid the reference + dereference bit around the map
? At first I tried just calling values
directly on the return from map
but Perl won't have it:
Type of arg 1 to values must be hash (not map iterator) at script\workbench.pl line 55, near "@obs ;"
The problem is that values
really, really wants a hash to operate on. That's because it's special: it clears the place holder used by each
. It needs an actual object to clear that on.
You can go one of two ways here. First, if you don't like the ref/deref, you could just pull the creation of the temporary hash out of the one-liner (please pick a better name than %h
for your actual code):
my %h = map { $_->{id} => $_->{value} } @obs;
say for values %h;
If you don't want %h
to hang around, just drop it into a temporary block:
...code code code...
{
my %h = map { $_->{id} => $_->{value} } @obs;
say for values %h;
}
...code code code...
Another approach could be to emulate what your temporary hash creation and values
is doing:
my %seen;
for ( reverse @obs ) { say $_->{value} unless $seen{$_->{id}}++ }
What really matters is what you're going to be doing with this data. If you just need the values of your inverted hash just once, then your one-liner may be the best solution. If you need this data (id & value) later on, then create the actual hash and use that -- don't do this transform more than once just so that you can keep them as one-liners.
Without further context, it's hard to give advice on which approach to take.
If values
were to work on a list, it would take every second element of that list. So
say for values %{{ map { $_->{id} => $_->{value} } @obs }};
would be
say for every_odd map { $_->{id} => $_->{value} } @obs;
Now, it's entirely possible to write such a function, but it's simply not needed in this case. One can simply do
say for map { $_->{value} } @obs;
And that simplifies to
say $_->{value} for @obs;
One catch: By not using a hash, you don't eliminate duplicates.
精彩评论