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

I want to sort this DATA from highest to lowest, on the first field. The sort works but only on the first number. For instance 9 is greater than 66 and 6 is greater than 57. If two fields are the same number, it will only print one of them, and I don't know where the extra characters come from at the end of the output. Please help.
print "Content-type: text/html\n\n"; while(<DATA>) { chomp; @sorted=(); @sorted = split(/\|/); $sorted{$sorted[0]} = [@sorted]; } print "$_->[0]|$_->[1]|$_->[2]<BR>\n" for sort {$b->[0] cmp $a->[0]} v +alues %sorted; __DATA__ 24|index.htm|http://localhost/~owner/index.htm 18|alertBoxes.htm|http://localhost/~owner/alertboxes.htm 4|andrewsGame.htm|http://localhost/~owner/andrewsgame.htm 3|bounceGame.htm|http://localhost/~owner/bouncegame.htm 21|browserRace.htm|http://localhost/~owner/browserrace.htm 6|breakFrames.htm|http://localhost/~owner/breakframes.htm 44|colorTables.htm|http://localhost/~owner/colortables.htm 61|humanReadable.htm|http://localhost/~owner/humanreadable.htm 27|mouseXY.htm|http://localhost/~owner/mousexy.htm 9|calculator.htm|http://localhost/~owner/calculator.htm 15|fakeFormat.htm|http://localhost/~owner/fakeformat.htm 2|makeCircle.htm|http://localhost/~owner/makecircle.htm 22|imageSwap.htm|http://localhost/~owner/imageswap.htm 5|easyDate.htm|http://localhost/~owner/easydate.htm 66|encoder.htm|http://localhost/~owner/encoder.htm 57|bgChanger.htm|http://localhost/~owner/bgchanger.htm 10|centipede.htm|http://localhost/~owner/centipede.htm 11|cookies.htm|http://localhost/~owner/cookies.htm

The output of this script is:

9|calculator.htm|http://localhost/~owner/calculator.htm 66|encoder.htm|http://localhost/~owner/encoder.htm 61|humanReadable.htm|http://localhost/~owner/humanreadable.htm 6|breakFrames.htm|http://localhost/~owner/breakframes.htm 57|bgChanger.htm|http://localhost/~owner/bgchanger.htm 5|easyDate.htm|http://localhost/~owner/easydate.htm 44|colorTables.htm|http://localhost/~owner/colortables.htm 4|andrewsGame.htm|http://localhost/~owner/andrewsgame.htm 3|bounceGame.htm|http://localhost/~owner/bouncegame.htm 27|mouseXY.htm|http://localhost/~owner/mousexy.htm 24|index.htm|http://localhost/~owner/index.htm 22|imageSwap.htm|http://localhost/~owner/imageswap.htm 21|browserRace.htm|http://localhost/~owner/browserrace.htm 2|makeCircle.htm|http://localhost/~owner/makecircle.htm 18|alertBoxes.htm|http://localhost/~owner/alertboxes.htm 15|fakeFormat.htm|http://localhost/~owner/fakeformat.htm 11|cookies.htm|http://localhost/~owner/cookies.htm 10|centipede.htm|http://localhost/~owner/centipede.htm ||

Replies are listed 'Best First'.
Re: Problem with sorting numbers.
by eibwen (Friar) on Apr 26, 2005 at 02:58 UTC

    Use <=> with a numeric sort, cmp with strings. See sort.

    Additionally, the reason repeated occurances aren't being printed is because you're using the occurance as the hash key. Given the above implementation you probably want to use an array instead of a hash.

Re: Problem with sorting numbers.
by ikegami (Patriarch) on Apr 26, 2005 at 03:00 UTC

    cmp compares strings. You should use <=> instead.

    Your code will only print one record if two have the same number, because the hash key $sorted[0] is not unique. The second (and third, etc) time you set a given hash element, the previously set value is lost. What follows is the same program, but it uses an array to avoid erasing records with the same number.

    use strict; use warnings; print "Content-type: text/html\n\n"; my @records; while (<DATA>) { chomp; push(@records, [ split(/\|/) ]); } print "$_->[0]|$_->[1]|$_->[2]<BR>\n" foreach sort { $b->[0] <=> $a->[0] } @records;
Re: Problem with sorting numbers.
by polettix (Vicar) on Apr 26, 2005 at 12:57 UTC
    and I don't know where the extra characters come from at the end of the output
    You aren't using warnings, are you? :) You may have one or more extra newlines at the end of your data, which get inserted as empty arrays.

    You may consider skipping empty lines:

    # From ikegami's code while (<DATA>) { chomp; push(@records, [ split(/\|/) ]) unless /^\s*$/; }

    Flavio (perl -e 'print(scalar(reverse("\nti.xittelop\@oivalf")))')

    Don't fool yourself.
Re: Problem with sorting numbers.
by Anonymous Monk on Apr 26, 2005 at 03:06 UTC
    That worked great! Thanks.