Beefy Boxes and Bandwidth Generously Provided by pair Networks
Problems? Is your data what you think it is?

(tye)Re: Sorting by_number

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

in reply to Sorting by_number

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")

Log In?

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://112524]
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others goofing around in the Monastery: (4)
As of 2024-06-22 23:04 GMT
Find Nodes?
    Voting Booth?

    No recent polls found

    erzuuli‥ 🛈The London Perl and Raku Workshop takes place on 26th Oct 2024. If your company depends on Perl, please consider sponsoring and/or attending.