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

I have the following hash:

$data{$meas_name}{$suffix_name}{$corner}{'value'}

Example:

$data{'meas_1'}{'suffix_1'}{'C1'}{'value'} = 10.2 $data{'meas_1'}{'suffix_2'}{'C1'}{'value'} = 4.7 $data{'meas_1'}{'suffix_3'}{'C1'}{'value'} = 5.2 $data{'meas_1'}{'suffix_4'}{'C1'}{'value'} = 11.8 $data{'meas_1'}{'suffix_5'}{'C1'}{'value'} = 0.7

There will be multiple values for the $meas_name field, multiple suffixes for each meas name, and multiple corners. Each corner will have the same number of suffixes for a given meas name. From the above, I would like to create a new hash of arrays with the following structure:

$ordered_hash{$meas_name}{$corner_name} = ("suffix_4", "suffix_1", "su +ffix_3", "suffix_2", "suffix_5")

That is, for each value of meas and corner, the new hash of arrays contains an ordered list of suffixes that correspond to the values in the {'value'} field sorted from smallest to largest. I know how to solve this problem if the original hash was created as $data{$meas_name}{$corner}{$suffix_name}{'value'} rather than $data{$meas_name}{$suffix_name}{$corner}{'value'} - I could simply use 3 foreach loops and a sort command to sort the original hash by the {'value'} field. The problem is that I need the hash to be ordered as it has been created above because I need to print it out in that order at the very end of my script.

Replies are listed 'Best First'.
Re: need help sorting a multilevel hash by a particular key
by tangent (Parson) on Dec 13, 2013 at 00:22 UTC
    A bit long winded perhaps:
    my %hash; while (my ($meas_name,$suffix) = each %data) { while (my ($suffix_name,$corner) = each %$suffix) { while (my ($corner_name,$value) = each %$corner) { push(@{ $hash{$meas_name}{$corner_name} }, $value->{'value +'}); } } } while (my ($meas_name,$corner) = each %hash) { while (my ($corner_name,$ary) = each %$corner) { @$ary = sort { $a <=> $b } @$ary; } }
Re: need help sorting a multilevel hash by a particular key
by kcott (Archbishop) on Dec 13, 2013 at 11:33 UTC

    G'day Special_K,

    Your prosaic description of the data structure is not entirely clear. I've made the assumption that "Each corner will have the same number of suffixes for a given meas name." means you have a structure like this:

    { meas_1 => { suffix_1 => { C1 => { value => 10.2 }, C2 => { value => 110.2 } }, suffix_2 => { C1 => { value => 4.7 }, C2 => { value => 204.7 } }, suffix_3 => { C1 => { value => 5.2 }, C2 => { value => 305.2 } }, suffix_4 => { C1 => { value => 11.8 }, C2 => { value => 411.8 } }, suffix_5 => { C1 => { value => 0.7 }, C2 => { value => 500.7 } }, }, }

    If that assumption is incorrect, please provide a clearer description of what you do have (showing example data instead of a narrative).

    Based on my assumption, this code does what you want:

    #!/usr/bin/env perl use strict; use warnings; my (%data, %ordered_hash); $data{meas_1}{suffix_1}{C1}{value} = 10.2; $data{meas_1}{suffix_2}{C1}{value} = 4.7; $data{meas_1}{suffix_3}{C1}{value} = 5.2; $data{meas_1}{suffix_4}{C1}{value} = 11.8; $data{meas_1}{suffix_5}{C1}{value} = 0.7; $data{meas_1}{suffix_1}{C2}{value} = 110.2; $data{meas_1}{suffix_2}{C2}{value} = 204.7; $data{meas_1}{suffix_3}{C2}{value} = 305.2; $data{meas_1}{suffix_4}{C2}{value} = 411.8; $data{meas_1}{suffix_5}{C2}{value} = 500.7; for my $meas (keys %data) { my @suffixes = keys %{$data{$meas}}; for my $corner (keys %{$data{$meas}{$suffixes[0]}}) { push @{$ordered_hash{$meas}{$corner}}, map { $_->[0] } sort { $b->[1] <=> $a->[1] } map { [ $_ => $data{$meas}{$_}{$corner}{value} ] } @suffix +es; } } use Data::Dump; dd \%ordered_hash;

    Output:

    { meas_1 => { C1 => ["suffix_4", "suffix_1", "suffix_3", "suffix_2", "suffix_5"] +, C2 => ["suffix_5", "suffix_4", "suffix_3", "suffix_2", "suffix_1"] +, }, }

    -- Ken

Re: need help sorting a multilevel hash by a particular key
by BrowserUk (Patriarch) on Dec 13, 2013 at 15:18 UTC

    First construct a list of anonymous arrays containing just the information needed -- name|suffix|corner|value -- then sort, then build your final hash:

    #! perl -slw use strict; use Data::Dump qw[ pp ]; my %hohohoh = map{ 'meas_'.$_ => { map { 'suffix_' . $_ => { map { 'C' . $_ => { value => rand 20 } } 1 .. 4 } } 1 .. 3 } } 1 .. 2; pp \%hohohoh; my %ordered; push @{ $ordered{ $_->[0] }{ $_->[ 2 ] } }, $_->[1] for sort { $a->[2] cmp $b->[2] || $a->[3] <=> $b->[3] } map { my $name = $_; map{ my $suffix = $_; map[ $name, $suffix, $_, $hohohoh{$name}{$suffix}{$_}{value} ], keys %{ $hohohoh{$name}{$suffix } }; } keys %{ $hohohoh{$name} }; } keys %hohohoh; pp \%ordered; __END__ C:\test>junk62 { meas_1 => { suffix_1 => { C1 => { value => "16.4599609375" }, C2 => { value => "18.387 +451171875" }, C3 => { value => "14.3621826171875" }, C4 => { value => "15. +8447265625" }, }, suffix_2 => { C1 => { value => "9.144287109375" }, C2 => { value => "8.103 +6376953125" }, C3 => { value => "8.3502197265625" }, C4 => { value => "5.13 +24462890625" }, }, suffix_3 => { C1 => { value => "5.531005859375" }, C2 => { value => "12.16 +85791015625" }, C3 => { value => "18.5546875" }, C4 => { value => "1.1138916 +015625" }, }, }, meas_2 => { suffix_1 => { C1 => { value => "16.4349365234375" }, C2 => { value => "7.0 +1171875" }, C3 => { value => "19.0521240234375" }, C4 => { value => "1.4 +508056640625" }, }, suffix_2 => { C1 => { value => "19.193115234375" }, C2 => { value => "19.6 +575927734375" }, C3 => { value => "1.6729736328125" }, C4 => { value => "1.95 +25146484375" }, }, suffix_3 => { C1 => { value => "2.4798583984375" }, C2 => { value => "5.77 +20947265625" }, C3 => { value => "4.3511962890625" }, C4 => { value => "4.02 +099609375" }, }, }, } { meas_1 => { C1 => ["suffix_3", "suffix_2", "suffix_1"], C2 => ["suffix_2", "suffix_3", "suffix_1"], C3 => ["suffix_2", "suffix_1", "suffix_3"], C4 => ["suffix_3", "suffix_2", "suffix_1"], }, meas_2 => { C1 => ["suffix_3", "suffix_1", "suffix_2"], C2 => ["suffix_3", "suffix_1", "suffix_2"], C3 => ["suffix_2", "suffix_3", "suffix_1"], C4 => ["suffix_1", "suffix_2", "suffix_3"], }, }

    With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.