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

hi

i thought i've found someting in the archiv, but this won't work for me, because all of the hashes have different keys i don't care about

i want the array to evolve from this:
%{array[0]} = { key1 => 1, key2 => 4 }; %{array[1]} = { key3 => 8, key4 => 4, key5 => 6 }; %{array[2]} = { key6 => 3 };
to this:
%{array[0]} = { key6 => 3 }; %{array[1]} = { key3 => 8, key4 => 1, key5 => 6 }; %{array[2]} = { key1 => 1, key2 => 24 };
well, it works with this:
sub SortArrayOfHashes { my @array = @{(shift)} ; my %valuesum; foreach my $i (0 .. $#array) { my $sum = 0; $sum += $_ foreach (values %{$array[$i]}); $valuesum{$i} = $sum; } my @sortedarray; foreach ( sort {$valuesum{$a} <=> $valuesum{$b} } keys %valuesum ) + { push (@sortedarray, $array[$_]); } return @sortedarray; }
but i believe there must be an easier way
any ideas how to optimize this?
slayven

Replies are listed 'Best First'.
Re: sorting an array of hashes by values but ...
by chromatic (Archbishop) on Feb 08, 2001 at 00:08 UTC
    You want the Schwartzian Transform. It looks to me like you want to sort the hash references by the sums of their values. (If I'm incorrect, you still probably want the Transform. You just won't be able to use my code. :)
    my @hashes = ( { key1 => 1, key2 => 4 }, { key3 => 8, key4 => 4, key5 => 6 }, { key6 => 3 }, ); sub sum { my $sum; $sum += $_ for (@_); return $sum; } @hashes = map { $_->[0] } sort { $a->[1] <=> $b->[1] } map { [ $_, sum( values %$_) ] } @hashes; use Data::Dumper; print Dumper(\@hashes);
    It takes a bit of thought to figure it out, but once you do, you'll have scary Perl kung-fu. The trick is adding extra data, sorting on that extra data, then discarding the extra data.
      wow
      i never understood (well, actually i've never tried to understand) the schwartzian transform. it has always been far above my skills
      tnx chromatic for forcing me to figure it out by solving one of my problems.

      now i can feel the source in me ;)

      slay
(tye)Re: sorting an array of hashes by values but ...
by tye (Sage) on Feb 08, 2001 at 00:07 UTC

    That seems mostly like the way to do it. Here are some minor improvements:

    sub SortArrayOfHashes { my $av= shift; my @sum= map { my $sum = 0; $sum += $_ foreach values %$_; $sum; } @$av; my @idx= sort { $sum[$a] <=> $sum[$b] } 0..$#sum; return @{$av}[@idx]; }

    You could also do a Schwartzian Transform, but that would make it slower (though a bit spiffier).

    Note that my version avoids copying the values so it might be possible to modify elements of the original array by modifying elements of the sorted array.

            - tye (but my friends call me "Tye")
Re: sorting an array of hashes by values but ...
by slayven (Pilgrim) on Feb 07, 2001 at 23:58 UTC
    argh
    sorry, the values of the array should not change
    this is the sorted array:
    %{array[0]} = { key6 => 3 }; %{array[1]} = { key1 => 1, key2 => 4 }; %{array[2]} = { key3 => 8, key4 => 4, key5 => 6 };
    ... i hope