sort

Discussion in 'Perl Misc' started by Pietro, Aug 11, 2005.

  1. Pietro

    Pietro Guest

    Hallo, I made a little script that sort the lines of a file:

    #! /usr/bin/perl

    sub numerically {$a <=> $b;}

    @array = <>;

    @array = sort numerically (@array);

    print (@array);

    Maybe the code is not so good, but why if I give thi input file:

    1.3.5.6
    1.1.2.4
    111.222.444.555
    1.2.5.6
    11.22.44.55
    1.2.3.4
    11.23.66.77
    11.22.33.44
    111.222.333.444
    11.22.44.55
    111.223.333.444
    11.22.33.44
    1.2.3.4
    11.22.22.22
    11.22.55.66
    1.2.4.5
    111.222.555.666
    1.1.2.3
    1.3.4.5

    The result is this:

    1.1.2.4
    1.1.2.3
    1.2.5.6
    1.2.3.4
    1.2.3.4
    1.2.4.5
    1.3.5.6
    1.3.4.5
    11.22.44.55
    11.22.33.44
    11.22.44.55
    11.22.33.44
    11.22.22.22
    11.22.55.66
    11.23.66.77
    111.222.444.555
    111.222.333.444
    111.222.555.666
    111.223.333.444

    As I see perl sots only the first two field delimited by a ".", the others
    are inserted as a fifo, first line encountered first line wrote in output,
    why doesn't perl compare all the line?

    Thanks, Pietro.
    --
    I will build myself a copper tower
    With four ways out and no way in
    But mine the glory, mine the power
    (So I chose AmigaOS and GNU/Linux)
    Pietro, Aug 11, 2005
    #1
    1. Advertising

  2. Pietro wrote:

    > sub numerically {$a <=> $b;}
    >
    > Maybe the code is not so good, but why if I give thi input file:
    >
    > 1.3.5.6
    > 1.1.2.4
    > 111.222.444.555


    > As I see perl sots only the first two field delimited by a ".", the others
    > are inserted as a fifo, first line encountered first line wrote in output,


    No, Perl sort the strings as numbers. If you convert the string
    '1.3.5.6' to a number then you get the number 1.3 (and you'll get a
    warning too if you've enabled warnings.

    Sounds to me like you may want to compare the strings as IP address.

    There are modules on CPAN to manipulate IP addresses.
    Brian McCauley, Aug 11, 2005
    #2
    1. Advertising

  3. Pietro wrote:
    > As I see perl sots only the first two field delimited by a ".", the others
    > are inserted as a fifo, first line encountered first line wrote in output,
    > why doesn't perl compare all the line?


    You're using a *numeric* sort. "1.3.5.6" etc are not numbers.

    If you had "use warnings;", you would see a load of these:

    Argument "1.1.2.4\n" isn't numeric in numeric comparison (<=>)

    Steve
    Stephen Hildrey, Aug 11, 2005
    #3
  4. Pietro wrote:
    > Hallo, I made a little script that sort the lines of a file:
    >
    > #! /usr/bin/perl
    > sub numerically {$a <=> $b;}
    > @array = <>;
    > @array = sort numerically (@array);
    > print (@array);
    >
    > Maybe the code is not so good, but why if I give thi input file:
    >
    > 1.3.5.6
    > 1.1.2.4

    [...]
    > 111.222.555.666
    > 1.1.2.3
    > 1.3.4.5
    >
    > The result is this:
    >
    > 1.1.2.4
    > 1.1.2.3
    > 1.2.5.6

    [...]
    > 111.222.444.555
    > 111.222.333.444
    > 111.222.555.666
    > 111.223.333.444
    >
    > As I see perl sots only the first two field delimited by a ".",


    Well, no. Perl is sorting _numerically_, just as you asked it to do.
    And the numerical value of e.g. the string 1.3.4.5 happens to be 1.3.

    > the
    > others are inserted as a fifo, first line encountered first line
    > wrote in output,


    Yep, that's a great feature. It is called a 'stable sort'. If two items have
    the same sort value, e.g. 111.222.444.555 and 111.222.333.444 which both
    have the value of 111.222, then since version 5.8 perl ensures that their
    relative position is not changed. Comes in very handy if you have to sort by
    multiple keys, e.g. first by first name, then by last name.

    > why doesn't perl compare all the line?


    But perl does compare all the line. Or rather the numerical value of the
    line just as you told it to do.

    jue
    Jürgen Exner, Aug 11, 2005
    #4
  5. Pietro wrote:

    > Maybe the code is not so good, but why if I give thi input file:
    >
    > 1.3.5.6
    > 1.1.2.4
    > 111.222.444.555
    > 1.2.5.6
    > 11.22.44.55
    > 1.2.3.4
    > 11.23.66.77
    > 11.22.33.44
    > 111.222.333.444
    > 11.22.44.55
    > 111.223.333.444
    > 11.22.33.44
    > 1.2.3.4
    > 11.22.22.22
    > 11.22.55.66
    > 1.2.4.5
    > 111.222.555.666
    > 1.1.2.3
    > 1.3.4.5
    >
    > The result is this:
    >
    > 1.1.2.4
    > 1.1.2.3
    > 1.2.5.6
    > 1.2.3.4
    > 1.2.3.4
    > 1.2.4.5
    > 1.3.5.6
    > 1.3.4.5
    > 11.22.44.55
    > 11.22.33.44
    > 11.22.44.55
    > 11.22.33.44
    > 11.22.22.22
    > 11.22.55.66
    > 11.23.66.77
    > 111.222.444.555
    > 111.222.333.444
    > 111.222.555.666
    > 111.223.333.444
    >
    > As I see perl sots only the first two field delimited by a ".", the others
    > are inserted as a fifo, first line encountered first line wrote in output,
    > why doesn't perl compare all the line?


    Pietro, I think it would be easier using Ruby.

    ----- program starts here -----

    puts DATA.read.sort_by{ |x| x.split('.').map{|s| s.to_i} }

    __END__
    1.3.5.6
    1.1.2.4
    111.222.444.555
    1.2.5.6
    11.22.44.55
    1.2.3.4
    11.23.66.77
    11.22.33.44
    111.222.333.444
    11.22.44.55
    111.223.333.444
    11.22.33.44
    1.2.3.4
    11.22.22.22
    11.22.55.66
    1.2.4.5
    111.222.555.666
    1.1.2.3
    2.3.4.5
    ----- program ends here -----

    The output is:

    1.1.2.3
    1.1.2.4
    1.2.3.4
    1.2.3.4
    1.2.4.5
    1.2.5.6
    1.3.5.6
    2.3.4.5
    11.22.22.22
    11.22.33.44
    11.22.33.44
    11.22.44.55
    11.22.44.55
    11.22.55.66
    11.23.66.77
    111.222.333.444
    111.222.444.555
    111.222.555.666
    111.223.333.444
    William James, Aug 12, 2005
    #5
  6. Pietro

    Eric Amick Guest

    On Thu, 11 Aug 2005 21:38:20 GMT, Pietro <> wrote:

    >Hallo, I made a little script that sort the lines of a file:
    >
    >#! /usr/bin/perl
    >
    >sub numerically {$a <=> $b;}
    >
    >@array = <>;
    >
    >@array = sort numerically (@array);
    >
    >print (@array);
    >
    >Maybe the code is not so good, but why if I give thi input file:
    >
    >1.3.5.6
    >1.1.2.4
    >111.222.444.555
    >1.2.5.6
    >11.22.44.55
    >1.2.3.4
    >11.23.66.77
    >11.22.33.44
    >111.222.333.444
    >11.22.44.55
    >111.223.333.444
    >11.22.33.44
    >1.2.3.4
    >11.22.22.22
    >11.22.55.66
    >1.2.4.5
    >111.222.555.666
    >1.1.2.3
    >1.3.4.5
    >
    >The result is this:
    >
    >1.1.2.4
    >1.1.2.3
    >1.2.5.6
    >1.2.3.4
    >1.2.3.4
    >1.2.4.5
    >1.3.5.6
    >1.3.4.5
    >11.22.44.55
    >11.22.33.44
    >11.22.44.55
    >11.22.33.44
    >11.22.22.22
    >11.22.55.66
    >11.23.66.77
    >111.222.444.555
    >111.222.333.444
    >111.222.555.666
    >111.223.333.444
    >
    >As I see perl sots only the first two field delimited by a ".", the others
    >are inserted as a fifo, first line encountered first line wrote in output,
    >why doesn't perl compare all the line?


    Because you told it to compare numbers, and numbers have at most one
    decimal point. If your goal is to compare the delimited fields, use a
    function like this:

    sub compare {
    my @value1 = split /\./, $a;
    my @value2 = split /\./, $b;
    ($value1[0] <=> $value2[0]) ||
    ($value1[1] <=> $value2[1]) ||
    ($value1[2] <=> $value2[2]) ||
    ($value1[3] <=> $value2[3]);
    }

    --
    Eric Amick
    Columbia, MD
    Eric Amick, Aug 12, 2005
    #6
  7. Pietro

    Pietro Guest

    On Thu, 11 Aug 2005 21:52:53 -0400, Eric Amick wrote:

    > Because you told it to compare numbers, and numbers have at most one
    > decimal point. If your goal is to compare the delimited fields, use a
    > function like this:
    >
    > sub compare {
    > my @value1 = split /\./, $a;
    > my @value2 = split /\./, $b;
    > ($value1[0] <=> $value2[0]) ||
    > ($value1[1] <=> $value2[1]) ||
    > ($value1[2] <=> $value2[2]) ||
    > ($value1[3] <=> $value2[3]);
    > }


    Thanks to all, now I have understood (above all I did not use -w).

    Bye, Pietro.
    --
    I will build myself a copper tower
    With four ways out and no way in
    But mine the glory, mine the power
    (So I chose AmigaOS and GNU/Linux)
    Pietro, Aug 12, 2005
    #7
  8. Pietro

    J. Gleixner Guest

    Pietro wrote:

    > Thanks to all, now I have understood (above all I did not use -w).


    If it's IP addresses that you're trying to sort, use the already
    provided, and very fast, sort_by_ip_address method from Net::Netmask:

    If it's not IP addresses, and your data just happened to look like it,
    then, nevermind. :)
    J. Gleixner, Aug 12, 2005
    #8
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. nobody
    Replies:
    0
    Views:
    536
    nobody
    Jun 1, 2004
  2. JerryJ
    Replies:
    11
    Views:
    1,405
    Dave Moore
    Apr 28, 2004
  3. John Black
    Replies:
    6
    Views:
    2,059
    John Harrison
    May 28, 2004
  4. Angus Comber
    Replies:
    7
    Views:
    1,157
    Richard Heathfield
    Feb 5, 2004
  5. Navin
    Replies:
    1
    Views:
    690
    Ken Schaefer
    Sep 9, 2003
Loading...

Share This Page