Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl: the Markov chain saw

Re: (tye)Re: Sorting by_number

by ncw (Friar)
on Sep 15, 2001 at 12:04 UTC ( [id://112606]=note: print w/replies, xml ) Need Help??

in reply to (tye)Re: Sorting by_number
in thread Sorting by_number

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

Replies are listed 'Best First'.
(tye)Re2: Sorting by_number
by tye (Sage) on Sep 15, 2001 at 22:24 UTC

    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://112606]
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others chilling in the Monastery: (3)
As of 2024-05-27 07:39 GMT
Find Nodes?
    Voting Booth?

    No recent polls found