[Cologne-pm] Sorting a hash by the hash value

Michael Lamertz mike at lamertz.net
Sun Nov 6 15:07:14 PST 2005


*Hurm*

Ok, ich gehe 'mal von besten Absichten aus, ein bischen Leben durch
Inhalte auf die Liste zu bringen, aber ein paar Anmerkungen:

> #  Copyright 1998 DevDaily Interactive, Inc.  All Rights Reserved.

Der Code ist 7 Jahre alt, und eine more perlish Loesung hat es, obwohl
die Frage noch immer wieder und wieder auf beginner's Listen auftaucht,
in dieser Zeit sogar in die FAQ geschafft:

    ---------- perldoc -q 'sort.*hash|hash.*sort' ----------
    Found in /usr/share/perl/5.8/pod/perlfaq4.pod
       How do I sort a hash (optionally by value instead of key)?

       Internally, hashes are stored in a way that prevents you from
       imposing an order on key-value pairs.  Instead, you have to sort
       a list of the keys or values:

           @keys = sort keys %hash;    # sorted by key
           @keys = sort {
                           $hash{$a} cmp $hash{$b}
                   } keys %hash;       # and by value

       Here we'll do a reverse numeric sort by value, and if two keys
       are identical, sort by length of key, or if that fails, by
       straight ASCII comparison of the keys (well, possibly modified by
       your locale--see perllocale).

           @keys = sort {
                       $hash{$b} <=> $hash{$a}
                                 ||
                       length($b) <=> length($a)
                                 ||
                             $a cmp $b
           } keys %hash;

       How can I always keep my hash sorted?

       You can look into using the DB_File module and tie() using the
       $DB_BTREE hash bindings as documented in "In Memory Databases" in
       DB_File.  The Tie::IxHash module from CPAN might also be
       instructive.
    ---------- perldoc -q 'sort.*hash|hash.*sort' ----------

Meine Version des Programmes, dessen Urheber uebrigens das Konzept der
anonymous sub-ref nicht kapiert hat, lautet

    ---------- snip ----------
    my %grade = (
        student1 => 90,
        student2 => 75,
        student3 => 96,
        student4 => 55,
        student5 => 76,
    );

    print "Ascending:\n",  map { "\t$_ => $grade{$_}\n" } sort { $grade{$a} <=> $grade{$b} } keys %grade;
    print "Descending:\n", map { "\t$_ => $grade{$_}\n" } sort { $grade{$b} <=> $grade{$a} } keys %grade;
    ---------- snip ----------

Ich empfehle hierzu den Talk von Uri Guttman, gehalten auf der YAPC::EU in
Paris.  Dort hat er sich ueber die Balance zwischen wart- und lesbarem
Perl-Code auf der einen Seite, und "Baby-Code", der sich nicht traut, die
spracheigenen Idiome zu benutzen auf der anderen Seite, hinreichend
ausgelassen.

Die Variablenbezeichnung wuerde ich uebrigens im Singular formulieren,
da man i.d. Regel eher auf das einzelne Element zugreift, statt auf die
Gesamtmenge aller 'grades'.  Das liest sich dann leichter:

    $grade{Michael} vs. $grades{Michael}.

Das ist aber wie gesagt persoenliche Praeferenz, und haengt natuerlich
davon ab, welche "Sicht" auf die Daten ueberwiegt.  Ein elender Ketzer
koennte sich natuerlich jetzt 'nen Typeglob anlegen, und die Gesamtheit als
%grades ansprechen, den einzelnen aber als %grade.  ;-)


Und nochwas:  Wenn Ihr solche "Artikel" Quoted, dann bitte mit Quellennennung,
sonst fuehlt sich evtl. 'mal jemand gedissed, der seinen eigenen Code in
unserem Mail-Archiv ergoogelt.


Mike

--
Michael Lamertz                        |                 mlamertz at perl-ronin.de
Sandstr. 122                           |               http://www.perl-ronin.de
50226 Frechen                          |              +49 171 6900 310 (mobile)
Germany                                |              +49 2234 205947 (private)


More information about the Cologne-pm mailing list