### (tye)Re: Sorting by_number

by tye (Sage)
 on Sep 15, 2001 at 00:00 UTC ( #112524=note: print w/replies, xml ) Need Help??

See also How do I do a natural sort on an array?. I might do the above something like:

```my @sorted= grep { s#0(.{4})#unpack"N",\$1#ges; 1 } sort
grep { s#(\d+)#"0".pack"N",\$1#ge; 1 } @{[ @list ]};
Even though it is abusing grep a little. (:

- tye (but my friends call me "Tye")

Replies are listed 'Best First'.
Re: (tye)Re: Sorting by_number
by ncw (Friar) on Sep 15, 2001 at 12:04 UTC
Ha, a one liner - very clever! Well that is almost good apart from the fact that it modifies the array. It strips the leading 0s from embedded numeric strings, so in the exmple above a00 is modified to a0 which is bad :-(

You can solve this by recasting it as an Shwartzian transform thus :-

```my @sorted = map { \$_->[0] } sort { \$a->[1] cmp \$b->[1] }
map { (my \$a = \$_) =~ s#(\d+)#"0".pack"N",\$1#ge; [\$_, \$a] } @list;
This also gets rid of the offensive greps!

This is likely to go wrong if embedded numerics are > 232 a problem which isn't easily solvable. In my original method these numbers should be automatically upconverted to doubles by perl avoiding the problem.

People who are puzzling out the above might like to consider replacing "0".pack"N",\$1 with sprintf"%016d",\$1

Yes, for more robust versions of this, see the previously mentioned link.

Actually, dealing with non-negative integers beyond 2**32 or even that won't fit in a double (either accurately or at all) is rather easy. For example, ignoring the case of extra leading zeros again:

```my @sorted= grep { s#0.{4}(\d+)#\$1#gs; 1 } sort
grep { s#(\d+)#"0".pack("N",length\$1).\$1#ge; 1 } @{[ @list ]};
This deals with any sequence of nearly 2**31 digits (I won't commit beyond that because I'm not certain that all ports of Perl will have a length function that works beyond that -- not that even 2**31 is much of a practical limitation).

Note that it preserves leading zeros unlike the previous one-liner, but it doesn't sort them intuitively. To deal with extra leading zeros properly requires a bit more work, for example:

```my @sorted= grep { s#0.{4}(\d+),(0*)!#\$2\$1#gs; 1 } sort
grep { s#(0*)(\d+)#"0".pack("N",length\$2)."\$2,\$1!"#ge; 1 }
@{[ @list ]};

Also note that I intentionally did not use a Schwartzian Transform as it is rather slower and uses more memory.

- tye (but my friends call me "Tye")

Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://112524]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others making s'mores by the fire in the courtyard of the Monastery: (4)
As of 2022-05-27 19:43 GMT
Sections?
Information?
Find Nodes?
Leftovers?
Voting Booth?
Do you prefer to work remotely?

Results (97 votes). Check out past polls.

Notices?