Take the 2-minute tour ×

I have a hash of hashes, like so:

%hash = ( a  => { b => 1, c =>2, d => 3},
          a1 => { b => 11, c =>12, d => 13},
          a2 => { b => 21, c =>22, d => 23} )

I want to extract the "b" element and put it into an array. Right now, I am looping through the hash to do this, but I think I can improve efficiency slightly by using map instead. I'm pretty sure that if this was an array of hashes, I'd use something like this:

@hasharray = ( { b => 1, c =>2, d => 3},
@array = map { ($_->{b} => $_) } @hasharray

Forgive me if I'm wrong, I'm still learning how map works. But what I'd like to know is how would I go about mapping the hash of hashes? Is this even possible using map? I have yet to find any examples of doing this.

Even better, the next step in this code is to sort the array once it's populated. I'm pretty sure this is possible, but I'm not smart enough on using map to figure it out myself. How would I go about doing this all in one shot?

Thanks. Seth

share|improve this question
add comment

3 Answers

up vote 9 down vote accepted

This extracts and sorts all "b"s:

my @array = sort { $a <=> $b } map $_->{b}, values %hash;
share|improve this answer
That worked great, exactly what I was looking for. I replaced 26 lines of code with this one, and improved the performance of that function from about O(n) to O(1). Thanks! –  sgsax Aug 27 '10 at 16:15
Well, it still has to iterate through the values of the hash and sort them, so it's not actually O(1). –  Corey Aug 27 '10 at 21:48
add comment

Take your second solution, and substitute values %hash for @hasharray:

@array = map { ($_->{b} => $_) } values %hash;

(And don’t forget the ; to terminate the statement.)

share|improve this answer
add comment

This fills @array with a sorted list of array references, each containing the value of b and the hashref it came from.

my @array = sort {$$a[0] <=> $$b[0]}
            map  { [$$_{b} => $_] } 
            values %hash;

my @sorted_hashes = map {$$_[1]} @array;
share|improve this answer
$a->[0] is easier to read than $$a[0]; similarly $_->{b} rather than $$_{b}. –  Philip Potter Aug 27 '10 at 15:22
It's better to use the <=> operator instead of cmp when sorting numbers. –  eugene y Aug 27 '10 at 15:26
@eugene => good point, fixing. @Philip => I prefer the doubled sigils for two reasons. First, it holds with other forms of dereferencing like @$a[1, 2]. Second, the -> operator is used for method calls, so I prefer only using it in situations where code is called. –  Eric Strom Aug 27 '10 at 16:27
add comment

Your Answer


