views:

209

answers:

2
my $hash_ref = {
    one   => { val => 1, name => 'one'  },
    three => { val => 3, name => 'three'},
    two   => { val => 2, name => 'two'  },
};

I would like to sort $hash_ref such that a foreach would order them by

$hash_ref->{$key}->{'val'}

one
two
three

Any suggestions?

+8  A: 

@sorted_list is an array of references to the sorted hash elements:

 @sorted_list = sort { $a->{'val'} <=> $b->{'val'} } values %{$unsorted_hash_ref};

You can use it like so:

#!/usr/bin/perl

my $hash_ref = {
    one   => { val => 1, name => 'one' },
    three => { val => 3, name => 'three' },
    two   => { val => 2, name => 'two' },
};

foreach $elem ( sort { $a->{'val'} <=> $b->{'val'} } values %{$hash_ref} ) {
    print "$elem->{'val'} : $elem->{'name'}\n";
}

Output:

1 : one
2 : two
3 : three
Hayato
Heh. I was so consumed with conducting the sort based on the english numerical text that I didn't notice the 'val' subkey. Nevertheless, Lingua::EN::Words2Nums means that you don't have to have those subkeys at all -- you can do the sort purely on the higher level keys. :)
Ether
I never heard of Lingua! Very interesting though, I will have to take advantage of it sometime!
Hayato
A: 

Hash tables don't have any specific order. However, you can sort the keys in an array and use that to iterate through the hash:

my $hash_ref = {
    one => { val => 1, name => 'one'},
    three => { val => 3, name => 'three'},
    two => { val => 2, name => 'two'},
};

use strict;
use warnings;
use Lingua::EN::Words2Nums;

foreach my $key (sort { words2nums($a) <=> words2nums($b) } keys %$hash_ref)
{
    # do something with $hash_ref->{$key}
    print "processing key $key.\n";
}

You can define anything you like as a sort method; see perldoc -f sort for more details. Conversion from ordinal numerical text to arithmetic values is done with Lingua::EN::Words2Nums (it does cardinal numbers too).

Ether