views:

919

answers:

2

I have a Perl hash whose keys start with, or are, numbers.

If I use,

foreach my $key (sort keys %hash) {
    print $hash{$key} . "\n";
}

the list might come out as,

0
0001
1000
203
23

Instead of

0
0001
23
203
1000
+16  A: 
foreach my $key (sort { $a <=> $b} keys %hash) {
    print $hash{$key} . "\n";
}

The sort operation takes an optional comparison "subroutine" (either as a block of code, as I've done here, or the name of a subroutine). I've supplied an in-line comparison that treats the keys as numbers using the built-in numeric comparison operator '<=>'.

Paul Tomblin
To clarify a bit: the keys in your case are strings, and are sorted as strings. <=> operator interprets its arguments as numbers, converting strings to numbers as needed.This is the sense of much of perl's oddness: operators, rather than variables, are typed in perl.
Arkadiy
It's context rather than type. <=> evaluates it's operands in numeric context, while the default sort operator (cmp) evaluates them in scalar (i.e. string) context.
kixx
+4  A: 

Paul's answer is correct for numbers, but if you want to take it a step further and sort mixed words and numbers like a human would, neither cmp nor <=> will do. For example...

  9x
  14
  foo
  fooa
  foolio
  Foolio
  foo12
  foo12a
  Foo12a
  foo12z
  foo13a

Sort::Naturally takes care of this problem providing the nsort and ncmp routines.

Schwern