Question

@aoaoh;

$aoaoh[0][0]{21} = 31;
$aoaoh[0][0]{22} = 31;
$aoaoh[0][0]{23} = 17;

for $k (0 .. $#aoaoh) {
    for $i(0.. $#aoaoh) {
        for $val (keys %{$aoaoh[$i][$k]}) {
            print "$val=$aoaoh[$i][$k]{$val}\n";
        }
    }
}

The output is:

    22=31
    21=31
    23=17

but i expect it to be

    21=31
    22=31
    23=17

Please tell me where is this wrong.

Also how do I sort the values so that i get the output as

    23=17 
    22=31
    21=31 (if 2 keys have same value then key with higher value come first)
Was it helpful?

Solution

Sounds like you want:

for $val (sort keys %{$aoaoh[$i][$k]}) {

and:

for $val (reverse sort keys %{$aoaoh[$i][$k]}) {

Although from your comment it looks like you don't want a pure reverse sort. You want to create your own sort function:

for $val (sort {$aoaoh[$i][$k]->{$a} <=> $aoaoh[$i][$k]->{$b} || $a <=> $b} keys %{$aoaoh[$i][$k]}) {

OTHER TIPS

It sounds like you are expecting hashes to return their keys and values in the order defined, where there is no such guarantee in perl.

You can either implement a more complex data structure that handles some of the ordering for you, or put some more sorting logic in your display (instead of just looping), or load up a module to support ordered hashes, such as Tie::Hash::Indexed.

I would expect the Tie::Hash::Indexed implementation to look like so:

my @aoaoh;

use Tie::Hash::Indexed;
tie my %hash, 'Tie::Hash::Indexed';
$aoaoh[0][0] = \%hash;

$aoaoh[0][0]{21} = 31;
$aoaoh[0][0]{22} = 31;
$aoaoh[0][0]{23} = 17;

for $k (0 .. $#aoaoh) {
    for $i(0.. $#aoaoh) {
        for $val (keys %{$aoaoh[$i][$k]}) {
            print "$val=$aoaoh[$i][$k]{$val}\n";
        }
    }
}

I answered on of the other two exact same questions by this user, but it looks like this one is going to win so I'm answering here too.

From perlfaq4's answer to How do I sort an array by anything?


Supply a comparison function to sort() (described in sort in perlfunc):

@list = sort { $a <=> $b } @list;

The default sort function is cmp, string comparison, which would sort (1, 2, 10) into (1, 10, 2). <=>, used above, is the numerical comparison operator.

If you have a complicated function needed to pull out the part you want to sort on, then don't do it inside the sort function. Pull it out first, because the sort BLOCK can be called many times for the same element. Here's an example of how to pull out the first word after the first number on each item, and then sort those words case-insensitively.

@idx = ();
for (@data) {
    ($item) = /\d+\s*(\S+)/;
    push @idx, uc($item);
    }
@sorted = @data[ sort { $idx[$a] cmp $idx[$b] } 0 .. $#idx ];

which could also be written this way, using a trick that's come to be known as the Schwartzian Transform:

@sorted = map  { $_->[0] }
    sort { $a->[1] cmp $b->[1] }
    map  { [ $_, uc( (/\d+\s*(\S+)/)[0]) ] } @data;

If you need to sort on several fields, the following paradigm is useful.

@sorted = sort {
    field1($a) <=> field1($b) ||
    field2($a) cmp field2($b) ||
    field3($a) cmp field3($b)
    } @data;

This can be conveniently combined with precalculation of keys as given above.

See the sort article in the "Far More Than You Ever Wanted To Know" collection in http://www.cpan.org/misc/olddoc/FMTEYEWTK.tgz for more about this approach.

See also the question later in perlfaq4 on sorting hashes.

Answer for Q1 will be:

print "${$aoaoh[0][0]}{$_}=$_\n" for sort keys %{$aoaoh[0][0]};

what could be written as:

for (sort keys %{$aoaoh[0][0]}) {
    print "${$aoaoh[0][0]}{$_}=$_\n"
}

And the answer for Q2:

print "$_->[1]=$_->[0]\n" for
map { [$_->[0], $_->[1]] }
sort { $a->[0] cmp $b->[0] }
map { [ ${$aoaoh[0][0]}{$_}, $_ ] } keys %{$aoaoh[0][0]};
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top