XYZ
XYZ

Reputation: 59

Sorting files numerically in Perl

I would like to sort files numerically using Perl script.

My files looks like below:

1:file1:filed2
3:filed1:field2
10:filed1:field2
4:field1:field2
7:field1:field2

I would like to display it as:

1:file1:filed2
3:filed1:field2
4:field1:field2
7:field1:field2
10:filed1:field2

Upvotes: 0

Views: 313

Answers (3)

Sobrique
Sobrique

Reputation: 53478

The way sort works in perl, is that it works through your list, setting each element to $a and $b - then testing those. By default, it uses cmp which is an alphanumeric sort.

You've also got <=> which is a numeric sort, and the kind you're looking for. (Alpha sorts 10 ahead of 2 ).

So - all we need do is extract the numeric value of your key. There's a number of ways you could do this - the obvious being to take a subroutine that temporarily copies the variables:

#!/usr/bin/env perl
use strict;
use warnings;

sub compare_first_num {
   my ( $a1 ) = split ( /:/, $a ); 
   my ( $b1 ) = split ( /:/, $b );
   return $a1 <=> $b1;
}

print sort compare_first_num <>;

This uses <> - the magic filehandle - to read STDIN or files specified on command line.

Or alternatively, in newer perls (5.16+):

print sort { $a =~ s/:.*//r <=> $b =~ s/:.*//r } <>;

We use the 'substitute-and-return' operation to compare just the substrings we're interested in. (Numerically).

Upvotes: 2

serenesat
serenesat

Reputation: 4709

For simple and fast solution, use Sort::Key::Natural (fast natural sorting) module:

use warnings;
use strict;

use Sort::Key::Natural qw( natsort );

open my $fh, "<", "file.txt" or die $!;
my @files = natsort <$fh>;
close $fh;
print @files;

Output:

1:file1:filed2
3:filed1:field2
4:field1:field2
7:field1:field2
10:filed1:field2

Upvotes: 1

fugu
fugu

Reputation: 6578

Split on : and store in a hash of arrays. Then you can sort and print out the hash keys:

my %data;

while(<DATA>){
    my @field = split(/:/);
    $data{$field[0]} = [@field[1..2]];
}

print join (':', $_, @{$data{$_}}) for sort { $a <=> $b } keys %data;

print "\n";

1:file1:filed2
3:filed1:field2
4:field1:field2
7:field1:field2
10:filed1:field2

Upvotes: 1

Related Questions