Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl Monk, Perl Meditation

two order sort

by ag4ve (Monk)
on Mar 05, 2013 at 00:09 UTC ( #1021725=perlquestion: print w/replies, xml ) Need Help??
ag4ve has asked for the wisdom of the Perl Monks concerning the following question:

I'm trying to sort a hashref of arrays first by the number of elements in the array and then the total count in all elements:
use List::Util qw(reduce); my $scan = {a => [ 5, 6 ], b => [ 5, 10, 15 ], c = [ 100 ], d => [ 8, +9 ] }; foreach my $sip (sort { $scan->{$b} <=> $scan->{$a} or +(reduce { $b + $a } @{$scan->{$b}}) <=> +(reduce +{$b + $a } @{$scan->{$a}}) } (keys %$scan))

Should print b, d, a, c but idk what it's currently doing.

Replies are listed 'Best First'.
Re: two order sort
by choroba (Bishop) on Mar 05, 2013 at 00:17 UTC
    $scan->{$b} returns an array reference. You are comparing references which is not what you want. Change the first part of sort to
    $#{ $scan->{$b} } <=> $#{ $scan->{$a} }
    @{ $scan->{$b} } <=> @{ $scan->{$a} }
    لսႽ ᥲᥒ⚪⟊Ⴙᘓᖇ Ꮅᘓᖇ⎱ Ⴙᥲ𝇋ƙᘓᖇ
Re: two order sort
by AnomalousMonk (Chancellor) on Mar 05, 2013 at 01:05 UTC

    Multi-key sort, both in descending order:

    >perl -wMstrict -le "use List::Util qw(sum); ;; my $scan = { a => [ 5, 6 ], b => [ 5, 10, 15 ], c => [ 100 ], d => [ 8, 9 ] }; ;; my @sorted = map $_->[0], sort { $b->[1] <=> $a->[1] or $b->[2] <=> $a->[2] } map [ $_, scalar @{ $scan->{$_} }, sum @{ $scan->{$_} } ], keys %$scan ; ;; print qq{@sorted}; " b d a c
      you forgot to tell that your (Schwarzian) approach is not only better readable but much faster, because the sums are only calculated once per entry. =)

      Cheers Rolf

        A decorate-sort-undecorate or GRT (Guttman-Rosler Transform) approach would be even faster, but I forgot how to decorate for descending sort. It's probably somewhere in A Fresh Look at Efficient Perl Sorting. Must look it up...


        1. See also Sort::Maker.
        2. According to the Wikipedia article linked by LanX herein, "decorate-sort-undecorate" is just another term for "Schwartzian Transform".

Re: two order sort
by LanX (Bishop) on Mar 05, 2013 at 00:32 UTC
    out of curiosity: why do you use reduce instead of sum from List::Util ?

    Cheers Rolf

Re: two order sort
by salva (Abbot) on Mar 05, 2013 at 11:39 UTC
    The problem may be related to both sort and reduce using the same global variables $a and $b.

    In any case, you can use Sort::Key:

    use Sort::Key::Multi 'ru_ru_keysort'; # sort by two unsigned keys in r +everse order use List::Util 'sum'; my @sorted = ru_ru_keysort { my $l = $scan->{$_}; (scalar(@$l), sum(@$l)) } keys %$scan;

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://1021725]
Approved by Gangabass
and all is quiet...

How do I use this? | Other CB clients
Other Users?
Others making s'mores by the fire in the courtyard of the Monastery: (5)
As of 2018-06-22 02:24 GMT
Find Nodes?
    Voting Booth?
    Should cpanminus be part of the standard Perl release?

    Results (120 votes). Check out past polls.