I recently posted a question asking for help in sorting an array of hashes by the values of multiple hash keys. I generally received answers relating to the sort function, which at first glance appeared to work. However, a closer look revealed that the nature of the sort function causes any new sort done on something previously sorted causes all order from the previous sort to be discarded. I came up with the following to get around this problem. I'd be very interested to hear comments, and suggestions for improvement.
sub sorthasharray($$) { # takes reference to array of hashes, and arra +y of key names to sort by. my ($hasharray, $keylist) = @_; my $keyCount; # counter my $hashCount; # counter for $hashCount ( 0 .. $#$hasharray ) { # walk through the arr +ay for $keyCount ( 0 .. $#$keylist ) { # walk through the + keys if ( $$hasharray[$hashCount]{$$keylist[$keyCou +nt]} =~ /^\d*?\.??\d*?$/ ) { # check to see if this should be a nume +ric comparison my $zeros = 12 - (length($$hasharray[$ +hashCount]{$$keylist[$keyCount]})); # find out how many zeros we nee +d #to pad to the right to make a string comparison equivalent to a numer +ic comparison #(this isn't onehundred percent accurate, especially for float numbers +. Anyone want to take a crack at it? for $zeroCount ( 1 .. $zeros ) { $$hasharray[$hashCount]{sortke +y} .= "0"; # padd the zeros } } $$hasharray[$hashCount]{sortkey} .= $$hasharra +y[$hashCount]{$$keylist[$keyCount]}; # build sortkey by concatenatin +g all sort keys in order } } @$hasharray = sort { $$a{sortkey} cmp $$b{sortkey} } @$hasharr +ay; # do the sort for $hashCount ( 0 .. @$hasharray ) { delete $$hasharray[$hashCount]{sortkey}; # delete the + unneeded key from all the hashes } }

Replies are listed 'Best First'.
RE: Sort Array of Hashes by values of multiple hash keys.
by lhoward (Vicar) on Jun 19, 2000 at 19:38 UTC
    Unless I'm missing your point. Sorting an array of hashes by the values of multiple keys is easy:
    my @l=( {FN=>'Les',LN=>'Howard'}, {FN=>'Larry',LN=>'Wall'}, {FN=>'Randal',LN=>'Schwartz'}); foreach(sort {$$a{LN} cmp $$b{LN} or $$a{FN} cmp $$b{FN}} @l){ print "$$_{LN}, $$_{FN}\n"; }
    The above code sorts a lits of hashes (each hash containing first and last names) by last name and then first name. The order of the original @l is not altered.

      This works, of course, but on a long list the overhead of doing all of those hash lookups multiple times may start to effect performance.

      This would, therefore, be a great time to try out a Schwartzian Transform - which would look something like this:

      my @l = ({FN => 'Les', LN => 'Howard'}, {FN => 'Larry', LN => 'Wall'}, {FN => 'Randal', LN => 'Schwartz'}); my @sorted = map { $_->[2] } sort { $a->[1] cmp $b->[1] || $a->[0] cmp $b->[0] } map { [$_->{FN}, $_->{LN}, $_] } @l; foreach (@sorted) { print "$_->{LN}, $_->{FN}\n"; }

      --
      http://www.dave.org.uk

      European Perl Conference - Sept 22/24 2000
      http://www.yapc.org/Europe/
      Where were you when I needed this easy solution originally. Well done. (smacks himself upside the head.) Didn't think of using or... (nor did anyone else! :)
RE: Sort Array of Hashes by values of multiple hash keys.
by BBQ (Curate) on Jun 20, 2000 at 08:16 UTC
    I don't mean to be nasty here, but please mind the linefeeds?
    Its rather hard to follow the above just because of mere formatting.

    #!/home/bbq/bin/perl
    # Trust no1!