Beefy Boxes and Bandwidth Generously Provided by pair Networks
go ahead... be a heretic
 
PerlMonks  

Comparing numbers

by Anonymous Monk
on Nov 29, 2002 at 10:41 UTC ( [id://216475]=perlquestion: print w/replies, xml ) Need Help??

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

Hi, I'm trying to compare the numbers in a variable and return the two consecutive numbers with the greatest difference between them. e.g.
my $file = '3.34, 3.67, 4.75, 4.98'; foreach my $number ($file) { $number_counter++; $difference = $number - ($number - 1); }
SO in this case the program wants to return 3.67, 4.75 and the difference between them (1.08). Obviously the above code didn't work. Does anyone have any ideas??

Replies are listed 'Best First'.
Re: Comparing numbers
by fruiture (Curate) on Nov 29, 2002 at 11:06 UTC

    Your code won't work for several reasons: $file is a scalar and in the context of your foreach-loop it is a list of one element. $number will be a lexical alias for $file while the single iteration of the loop happens. $number_counter will be increased once and $difference will be assigned 1, for a-(a-1)==a-a+1==1 .

    Try this:

    my @number = qw(3.34 3.67 4.75 4.98); my $maxdiff = 0; my @index = (); foreach my $i ( 1 .. @number-1 ){ my $diff = abs( $number[$i] - $number[$i-1] ); if( $diff > $maxdiff ){ $maxdiff = $diff; @index = ($i-1,$i); } } if( @index ){ printf "%f: %f , %f\n", $maxdiff, @number[ @index ] }

    update: of course, see perlsyn and perldata

    --
    http://fruiture.de
       @index = ($i-1,$i);

      That's cute. My natural inclination would have been to keep just the index of the larger of the winning pair of consecutive numbers ($i). However, it costs very little to put the indices of both numbers aside and use them later to display the slice of interest from the array. :-)

Re: Comparing numbers
by rdfield (Priest) on Nov 29, 2002 at 11:53 UTC
    Well, where do we start?

    First up, foreach my $number ($file) is trying to iterate over a single value, ie the string '3.34, 3.67, 4.75, 4.98'. The code inside the loop is only going to see '3.34, 3.67, 4.75, 4.98' and not the individual values. Did you test this code? Did you put a print inside the loop to see what $number contained?

    So, what you're really looking for is to split up the string in $file into the individual values. Let's have a look in perlfunc to see if there's anything available to help us...look at that...a function called split. So far, so good. Let's see how that works...

    split /PATTERN/,EXPR,LIMIT
    split /PATTERN/,EXPR
    split /PATTERN/
    split
    
    Splits a string into a list of strings and returns that list
    
    That sounds like the business. So, if we apply split to $file we can get get the numbers out of it - cool! But, wait, what PATTERN to use? From looking at the contents of $file we can see that each number is seperated by ", ", sheesh, that was pretty easy. So we get the line:
    my @numbers = split /, /,$file;
    And how do we check that @numbers contains what we think it should? We could use a print statement, something like:
    print join("\n",@numbers) . "\n";
    or we could run our little script in the perl debugger perl -d difference.pl, assuming of course that you've created a file called 'difference.pl' and that you have perl installed on your computer.

    So what do we need to do next? We have to iterate over them calculating the differences. OK, how do we do that? The most obvious choice would be a foreach loop. And how should the iteration be defined? My personal choice would be to start from the second position and work towards the end, but you may have a different preference, it's entirely up to you - after all it's your homework and your grade. Using my choice of iteration definition gives us:

    foreach my $index (1 .. $#numbers)
    "Why 1?" I hear you say, "I though you said we were going to start at the second position?". We're starting at 1 because, in Perl, unless you specifically tell it otherwise, arrays are assumed to start at index 0, making index 1 the second index.

    Now we're getting somewhere. Next we have to compute the difference. That's pretty easy:

    my $difference = abs($numbers[$index] - $numbers[$index - 1]);
    Now all we have to do is to keep track of the maximum difference. My personal preference is to use the terniary operator "?:", but, again, your homework, your grade, so feel free to use your imagination and use any construct you feel comfortable with. Of course, we must remember to initialise the variable holding the maximum difference correctly, otherwise this work will all be for nothing.
    $max_difference = ($index == 1 or $difference > $max_difference)?$diff +erence:$max_difference;
    Finally, all we need to do now is to print the result:
    print "$max_difference\n";
    Putting the whole thing together (adding variable definitions and other appropriate code furniture):
    use strict; use warnings; my $file='3.34, 3.67, 4.75, 4.98'; my @numbers=split /, /,$file; my $max_difference; foreach my $index(1 .. $#numbers) { my $difference = abs($numbers[$index] - $numbers[$index - 1]); $max_difference = ($index == 1 or $difference > $max_difference)?$d +ifference:$max_difference; } print "$max_difference\n";
    Be sure to post back and let everyone know how your grade!

    rdfield

Re: Comparing numbers
by Chief of Chaos (Friar) on Nov 29, 2002 at 11:16 UTC
    Hi,
    sounds to me like homework.
    But ok.
    I would write it so :
    #!/usr/local/perl -w use strict; use warnings; my @file = ('0.13','0.14','0.14'); my $diff = 0; my @diffVal; for (my $i=1 ; $i< scalar(@file) ; $i++){ if ($diff < abs($file[$i-1]-$file[$i])){ $diff = abs($file[$i-1]-$file[$i]); $diffVal[0] = $file[$i-1]; $diffVal[1] = $file[$i]; } } print "Difference between $diffVal[0] and $diffVal[1] is $diff\n" if ( +defined($diffVal[1]));
    (It is not optimized!)
      What's the point of using -w and use warnings? And why quote numbers? Also, your code seems to fail if all numbers are equal - it won't generate output.

      Abigail

        ok, -w and use warnings don't make sense.
        Yes, you are correct with the equal - output and the numbers.
        change
        my @file = ('0.13','0.14','0.14'); my $diff = 0;
        to
        my @file = (0.14,0.14); my $diff = -1;
        and here you got your output
        Difference between 0.14 and 0.14 is 0

      You could also have some fun doing something like this:

      my @numbers = ('0.13', '0.14', '0.14', '0.19', '0.21', '0.23', '0.45') +; my %differences = (); for (my $i = 0; $i < scalar(@numbers); $i++) { next if $i == 0; push @{$differences{($numbers[$i] - $numbers[$i - 1])}}, $numb +ers[$i] . " - " . $numbers[$i - 1]; } foreach (sort keys %differences) { print STDOUT "Difference ($_) occured: ", join (', ', @{$diffe +rences{$_}}), "\n" } exit 0;

      I guess that's going beyond the exercise a little bit, but kind of fun and turned out this:

      Difference (0) occured: 0.14 - 0.14 Difference (0.01) occured: 0.14 - 0.13 Difference (0.02) occured: 0.21 - 0.19, 0.23 - 0.21 Difference (0.05) occured: 0.19 - 0.14 Difference (0.22) occured: 0.45 - 0.23
Re: Comparing numbers
by Abigail-II (Bishop) on Nov 29, 2002 at 11:17 UTC
    Eh, there's hardly anything correct in your program. Is this a homework problem? Anyway, I'd do something like:
    my @nums = qw /3.34 3.67 4.75 4.98/; my $diff = -1; for (my $i = 1; $i < @nums; $i ++) { my $d = abs ($nums [$i] - $nums [$i - 1]); $diff = $d if $diff < $d; } print "Greatest difference is $diff\n" unless $diff < 0;

    Note that the above code is untested.

    Abigail

Re: Comparing numbers
by Aristotle (Chancellor) on Nov 30, 2002 at 18:46 UTC
    Just for the sake of doing it differently, and because I so love List::Util. (Thanks to merlyn for mentioning it way back here on PM.) :)
    use List::Util qw(reduce); my @num = qw/3.34 3.67 4.75 4.98/; my @diff = map abs($num[$_-1] - $num[$_]), 1 .. $#num; my $maxidx = reduce { $diff[$a] > $diff[$b] ? $a : $b } 0 .. $#diff; print "|$num[$maxidx] - $num[$maxidx+1]| = $diff[$maxidx]\n" if @num > + 1;

    Makeshifts last the longest.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://216475]
Approved by virtualsue
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others musing on the Monastery: (4)
As of 2024-04-19 17:53 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found