tags:

views:

112

answers:

4

Let's say in Perl I have a list of hash references, and each is required to contain a certain field, let's say foo. I want to create a list that contains all the mappings of foo. If there is a hash that does not contain foo the process should fail.

@hash_list = (
 {foo=>1},
 {foo=>2}
);

my @list = ();
foreach my $item (@hash_list) {
   push(@list,$item->{foo});
}

#list should be (1,2);

Is there a more concise way of doing this in Perl?

+6  A: 

Yes. there is.

my @list = map {
    exists $_->{foo} ? $_->{foo} : die 'hashed lacked foo'
  }
  @hash_list
;
Evan Carroll
for complex map expressions like this, it is usually easier to read using the block syntax rather than the bare expression
Eric Strom
that's better +1, I use the bare syntax all the time for short expressions, probably the only long one that doesn't get a block is the case of a map that returns an arrayref: ` map [...] => ...`
Eric Strom
A: 
if ( @hash_list != grep { exists $_->{foo} } @hash_list ) {
    # test failed
}
eugene y
+1  A: 

Evan's answer is close, but will return the hashrefs rather than the value of foo.

my @list = map $_->{foo} grep { exists $_->{foo} } @hash_list
Daenyth
Yea, I fixed this. and, I also made it die, there is a disconnect between his code and his question. You can also do this with one loop.
Evan Carroll
+2  A: 

You can use the map function for this :

@hash_list = (
 {foo=>1},
 {foo=>2}
);

@list = map($_->{foo}, @hash_list);

map applies the function in the first argument over all element of the second argument.

grep is also cool to filter elements in a list and works the same way.

Peter Tillemans