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

Hi all, I have a problem in coding. I have the following file (each row is divided by ; in 5 fields):
.0000000001;2;1;.5;.2 .5;2;1;.5;.5 0.3;1.5;.5;.5;.2 1;1;.7;1;1 .4;1;.4;1;.5
I want to sort the rows in descending order according to their first field, so I typed the following script:
#!/usr/bin/perl use strict; use diagnostics; use warnings; my $fh; my @lines = (); my @sortedlines = (); open($fh, "<", "filename") or die "I cannot open the file: $!\n"; chomp(@lines = <$fh>); @sortedlines = sort { $b =~ /(^\d*\.*\d+);/ <=> $a =~ /(^\d*\.*\d+);/ +} @lines; print "SORTED LINES = @sortedlines\n";
but it doesn't work!
Where's the problem?
Thanks in advance,
Saverio

Replies are listed 'Best First'.
Re: Sorting file rows and copy them in an array
by choroba (Cardinal) on Dec 11, 2014 at 15:22 UTC
    The problem is context. The match operator /.../ returns various things depending on the presence of the /g modifier and the context, see perlop.

    In particular, you need to enforce list context somehow if you want the matching to return the matched part. So, use something like

    sort { ($a =~ /(\d+)/)[0] <=> ($b =~ /(\d+)/)[0] } sort { ($a =~ /\d+/g)[0] <=> ($b =~ /\d+/g)[0] } sort { (split /;/, $a)[0] <=> (split /;/, $b)[0] }

    It might be nicer to use the Schwartzian Transform or Orcish Maneuvre to avoid repeated matching:

    # ST my @sorted = map $_->[1], sort { $a->[0] <=> $b->[0] } map [ (split /;/)[0], $_], @lines; # OM use Syntax::Construct qw{ // }; my %cache; my @sorted = sort { $cache{$a} //= (split /;/, $a)[0] <=> $cache{$b} //= (split /;/, $b)[0] } @lines;

    Or, if you don't mind some warnings about non-numeric values, just compare the strings numerically directly:

    sort { $a <=> $b } @lines

    (All code untested.)

    لսႽ† ᥲᥒ⚪⟊Ⴙᘓᖇ Ꮅᘓᖇ⎱ Ⴙᥲ𝇋ƙᘓᖇ

      Hi,
      First, What does the /g modifier mean?
      Secondly, what does the [0] mean?

      saverio
        1. /g means "global". See perlop as already hinted.
          The /g modifier specifies global pattern matching—that is, matching as many times as possible within the string. How it behaves depends on the context. In list context, it returns a list of the substrings matched by any capturing parentheses in the regular expression. If there are no parentheses, it returns a list of all the matched strings, as if there were parentheses around the whole pattern.
        2. (...)[0] returns the first (zeroth) element of the list. Therefore, the construct enforces list context on the contents of the parentheses.
        لսႽ† ᥲᥒ⚪⟊Ⴙᘓᖇ Ꮅᘓᖇ⎱ Ⴙᥲ𝇋ƙᘓᖇ
Re: Sorting file rows and copy them in an array
by toolic (Bishop) on Dec 11, 2014 at 15:26 UTC
    Tested code, employing the Schwartzian_transform
    use warnings; use strict; use Data::Dumper; my @lines; chomp(@lines = <DATA>); my @sortedlines = map { $_->[0] } sort { $a->[1] <=> $b->[1] } map { [ $_, (split /;/)[0] ] } @lines; print Dumper(\@sortedlines); __DATA__ .0000000001;2;1;.5;.2 .5;2;1;.5;.5 0.3;1.5;.5;.5;.2 1;1;.7;1;1 .4;1;.4;1;.5

    Outputs:

    $VAR1 = [ '.0000000001;2;1;.5;.2', '0.3;1.5;.5;.5;.2', '.4;1;.4;1;.5', '.5;2;1;.5;.5', '1;1;.7;1;1' ];

    See also:

      Ok thank you to all for answers.