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

hi, how do i sort an array contains data like (1.1 11.2.3 2.3 11.2.1)? the result should be (1.1 2.3 11.2.1 11.2.3). the sort function in perl only does numeric or string sort. is there a quick and easy way to sort it? thanks.

Replies are listed 'Best First'.
Re: a sort question
by derby (Abbot) on Jun 06, 2007 at 18:52 UTC
Re: a sort question
by BrowserUk (Patriarch) on Jun 06, 2007 at 18:56 UTC

    If no individual element of the 'numbers' is > 255

    $/ = "\n";; print for map{ join '.', unpack 'C*', $_ } sort map{ pack 'C*', split '\.' } qw[1.1 11.2.3 2.3 11.2.1];; 1.1 2.3 11.2.1 11.2.3

    Update: In fact, utilising Unicode, this can handle individual number elements upto >64,000. Which ought to be enough as it would allow a 3-part version number to handle 1 new version every microsecond for a project life exceeding 8 years before it encountered problems.

    print for map{ join'.',unpack'U*',$_ } sort map{ pack'U*',split '\.', "1.2.$_.4" } reverse qw[ 1 11 111 127 127 128 129 254 255 256 257 1111 11111 6400 +0 ];; 1.2.1.4 1.2.11.4 1.2.111.4 1.2.127.4 1.2.127.4 1.2.128.4 1.2.129.4 1.2.254.4 1.2.255.4 1.2.256.4 1.2.257.4 1.2.1111.4 1.2.11111.4 1.2.64000.4

    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.
Re: a sort question
by duff (Parson) on Jun 06, 2007 at 18:58 UTC

    And just to clarify, perl's sort routine does not only do numeric or string sorting. It sorts based on any arbitrary criteria you choose as long as you're willing to write a binary tri-state comparator that has the same semantics as  <=> or cmp (i.e., returns -1 for less then, 0 for equal and 1 for greater than)

Re: a sort question
by salva (Canon) on Jun 06, 2007 at 19:38 UTC
Re: a sort question ("natural")
by tye (Sage) on Jun 06, 2007 at 19:58 UTC

    The search for natural sort turns up lots of ways to do this type of thing.

    - tye        

Re: a sort question
by Anonymous Monk on Jun 06, 2007 at 18:45 UTC
    sort { $a<=>$b || $a cmp $b } qw(1.1 40.5 10.3 11.5 11.1.1) that gets the correct result. but it also error Argument "11.1.1" isn't numeric in numeric comparison (<=>)
Re: a sort question
by varian (Chaplain) on Jun 07, 2007 at 09:20 UTC
    Just enhance the sort to work on arrays, something like this would do it:

    #!/usr/bin/perl use strict;use warnings; sub versionsort { my ($a,$b) = @_; my $diff; foreach (0..$#$a) { return 1 if !defined $b->[$_]; $diff = $a->[$_] <=> $b->[$_]; return $diff if $diff; } return @$a <=> @$b; } my @data = qw(1.1 11.2.3 2.3 11.2.1 11.2 11.2.1.1); print "before: ".join(', ',@data)."\n"; my @versions = map { [split '\.',$_] } @data; my @sorted = map { join '.',@$_} sort {versionsort($a,$b)} @versions; print "sorted: ".join(', ',@sorted)."\n";
    Outputs:
    before: 1.1, 11.2.3, 2.3, 11.2.1, 11.2, 11.2.1.1 sorted: 1.1, 2.3, 11.2, 11.2.1, 11.2.1.1, 11.2.3
Re: a sort question
by andreas1234567 (Vicar) on Jun 07, 2007 at 05:02 UTC
    Consider Sort::Versions, but do read tye's advice in this node about its shortcomings first.
    --
    print map{chr}unpack(q{A3}x24,q{074117115116032097110111116104101114032080101114108032104097099107101114})