http://www.perlmonks.org?node_id=510722

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

Hi there
I have a number of text files that look like something like this
0.2430 0.0830 0.1320 0.0920 0.0180 0.0880 0.3440
I would like to read though this text file and extract the two largest numbers .. in this case, 0.2430 and 0.3440. I've written the following script with this task in mind.
#!/usr/bin/perl $file = $ARGV[0]; open(FILE, "$file") || die "Error, can't open $file file: $!\n"; @input = <FILE>; $largest_value = 0; $second_value = 0; for($i = 0; $i < @input; $i++) { $value = substr($input[$i], 0, 6); if($value > $largest_value) { $largest_value= $value; } if(($value > $second_value) && ($value < $largest_value)) { $second_value = $value; } } print "$largest_value $second_value\n";
The program prints the largest value correctly, but selects 0.1320 rather than 0.2430 for the second largest value, which obviously isn't correct.
Any suggests as regards to what I am doing wrong much appreciated. Thanks.

Replies are listed 'Best First'.
Re: extracting the largest values
by Perl Mouse (Chaplain) on Nov 22, 2005 at 11:26 UTC
    Your problem is that if you find a new largest value, you completely forget the current largest value. Instead the current largest value should become the new second largest value, and the new largest value should become the new largest value. Something like (untested):
    if ($value > $largest_value) { ($largest_value, $second_value) = ($value, $largest_value); next; } if ($value > $second_value) { $second_value = $value; }
    If you go for a minimum amount of lines, you could also do:
    ($largest_value, $second_value) = sort {$a <=> $b} $largest_value, + $second_value, $value;
    Perl --((8:>*
Re: extracting the largest values
by svenXY (Deacon) on Nov 22, 2005 at 11:31 UTC
    Hi,
    you need to make the old largest number the second_largest if there is a new largest one.
    I fixed some other minor things as well.
    #!/usr/bin/perl -w use strict; my @input = <DATA>; chomp @input; my $largest_value = 0; my $second_value = 0; for (@input){ #$value = substr($input[$i], 0, 6); why? Perl can dwal with floati +ng point numbers if($_ > $largest_value){ $second_value = $largest_value; $largest_value= $_; } elsif(($_ > $second_value) && ($_ < $largest_value)){ $second_value = $_; } } print "$largest_value $second_value\n"; __DATA__ 0.2430 0.0830 0.1320 0.0920 0.0180 0.0880 0.3440
    prints
    0.3440 0.2430

    Regards,
    svenXY
Re: extracting the largest values
by Roy Johnson (Monsignor) on Nov 22, 2005 at 15:02 UTC
Re: extracting the largest values
by murugu (Curate) on Nov 22, 2005 at 13:35 UTC
    Hi Angharad,

    I think this do what you need,

    use strict; use warnings; my @input = <DATA>; chomp @input; my ($max, $s_max) = sort { $b<=>$a} @input; print $max,$",$s_max,$/; __DATA__ 0.2430 0.0830 0.1320 0.0920 0.0180 0.0880 0.3440

    Regards,
    Murugesan Kandasamy
    use perl for(;;);

      That could be rather inefficient if there are a lot of numbers.
      Perl --((8:>*
Re: extracting the largest values
by swkronenfeld (Hermit) on Nov 22, 2005 at 16:16 UTC
    I'd just like to point out the following...

    If you are using files that only contain numbers, the following *IX command prompt will do the work for you with no scripts

    sort -rn YourFileName | head -n 2

    I know this is a Perl board, but sometimes people get caught up writing unnecessary scripts. It sounds to me like you're trying to find these values in a file, but that this is an independent scripts (not passing the values off to another piece of perl). The above line saves you the trouble of debugging a script, and will prevent future maintainers from deciphering your code (unless it's well commented, which, of course, it will be :)