lobs has asked for the wisdom of the Perl Monks concerning the following question:

So I am trying to sort the inner hash(VBP, IN, VB, ...) value by ascending order I don't care for sorting the outer hash. This is what I get out of what I implemented
$VAR1 = { 'like' => { 'VBP' => '0.0882352941176471', 'IN' => '0.823529411764706', 'VB' => '0.0882352941176471' }, 'kind' => { 'JJ' => '0.2', 'NN' => '0.8' }, 'distribution' => { 'NN' => '1' }, 'successful' => { 'JJ' => '1' }, 'capped' => { 'JJ' => '0.666666666666667', 'VBN' => '0.333333333333333' }, ...
This is my code snippet
for $key( keys %bigrams) { for $secKey ( sort { $bigrams{$key}{$a} <=> $bigrams{$key}{$b} + } keys %{ $bigrams{$key} } ) { $bigrams{$key}{$secKey} = ($bigrams{$key}{$secKey}) / ($fr +eqs{$key}); } }
I've tried other examples on this site and it have yet to work. Thanks.

Replies are listed 'Best First'.
Re: Sort Hash of hashes
by davido (Cardinal) on Mar 22, 2016 at 21:32 UTC

    A plain old hash is an unordered container. Sorting the keys does not sort the container, it just gives you a sorted list of keys to work with. The underlying container is unaffected by your sort operation. The order you are seeing when you dump the structure is unreliable and should not be thought of as ordered.

    If you need output to be in a specific order you probably need to sort on output. I assume your goal is not to get Data::Dumper to output in a sorted order, but it does serve as a good example: By setting $Data::Dumper::Sortkeys = sub { ... }, you can control the sort order of the data being dumped. The trick will be to compose a subroutine that detects which levels should be sorted, and which should not, and that applies the sort algorithm that you've used in your example code only when appropriate.

    So that's how it could be done with Data::Dumper. Your specific use case will be different, but the idea is similar; rather than relying on the hash to be in a particular order, assure that you deal with its elements in the order you prefer.


    Dave

      I'm using Data::Dumper just to display the hash. To solve my problem, I'm storing the keys in the inner hash within an array but the value gets dropped. So I'll assume I'll have to store the value with the key.
Re: Sort Hash of hashes
by tangent (Parson) on Mar 22, 2016 at 23:52 UTC
    You can use another structure to store the sorted results, in this case a hash of arrays of arrays:
    my %sorted; for my $key (keys %bigrams) { my $hash = $bigrams{$key}; for my $secKey (sort { $hash->{$a}<=>$hash->{$b} } keys %$hash) { my $value = $hash->{$secKey} / $freqs{$key}; push( @{ $sorted{$key} }, [$secKey,$value] ); } } while ( my ( $key, $aoa ) = each %sorted ) { print "$key\n"; for my $ary ( @$aoa ) { print "\t$ary->[0] => $ary->[1]\n"; } }
    Result:
    like VBP => 0.0882352941176471 VB => 0.0882352941176471 IN => 0.823529411764706 kind JJ => 0.2 NN => 0.8 capped VBN => 0.333333333333333 JJ => 0.666666666666667 successful JJ => 1 distribution NN => 1
Re: Sort Hash of hashes
by Anonymous Monk on Mar 22, 2016 at 21:42 UTC
      I don't need to display the hash at all. Later on in the program I am storing just the key within an array,
      @tags = keys %{ $bigrams{$element}}
      Is there a way to sort the key by there value.
        Yes! here is a short program to illustrate the idea:
        #/usr/bin/perl use warnings; use strict; my %hash = (a => 4, b => 6, c => 2); my @sorted_keys = sort keys %hash; print "@sorted_keys\n"; my @sort_by_value = sort{my $A = $hash{$a}; my $B = $hash{$b}; $A <=> $B ## or cmp for strings }keys %hash; print "@sort_by_value\n"; __END__ Prints: a b c # simple key sort c a b # keys sorted by value of keys
        The sort{} takes input from the right and sends the same output to the left except in a different order. What goes inside the {} are the "rules" for how to sort the input. $a and $b are special Perl variables that are assigned various values as needed to sort the input. The "return value" of the sort {} should be <0,0,>0 just like the cmp statement does for strings or the "spaceship" operator, <=> does for numbers.