sort

P

Pietro

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.
 
B

Brian McCauley

Pietro said:
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.
 
S

Stephen Hildrey

Pietro said:
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
 
J

Jürgen Exner

Pietro said:
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
 
W

William James

Pietro said:
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
 
E

Eric Amick

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]);
}
 
P

Pietro

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.
 
J

J. Gleixner

Pietro said:
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. :)
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,768
Messages
2,569,574
Members
45,050
Latest member
AngelS122

Latest Threads

Top