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

Hi all, I'm atempting to process a file and identify values greater or less than a certain max or min. These values will be skipped when I plot the resulting file with gnuplot. I'm attempting to use 'map' to process the @data array below, but it doesn't appear to work the way I expect. For example, I know there are dud values associated with $data[4], so I set $maxreject[4] to true so that these values will have a "?" put in front of the value and therefore skipped when I use gnuplot. With the code below, no "?" is appended to the dud values. The code is:
use strict; @maxreject = (); @minreject = (); $maxreject[4] = 1; $maxclip = 1E-1; $minclip = -3.0E-6; $sdate = 20020106; $edate = 20020107; open(CLOCK,"data.log") || die "data: $!"; open(OUT,">out"); while(<CLOCK>) { chomp; my($time,$date,@data) = (split / +/)[1,2,6,7,9,12,13,14]; $date =~ m/(\d\d)-(\w+)-(\d{4})/; $day = $1; $month = $months{uc($2)}; $year = $3; $now = $year.$month.$day; last if($now > $edate); if($now >= $sdate) { $i=0; map { #? data is skiped when plotted if($maxreject[$i]) { $_ = "?$_" if($_ > $maxclip); } if($minreject[$i]) { $_ = "?$_" if($_ < $minclip); } $i++; } @data; print OUT "$day/$month $time @data\n" ; } } #end of while close(OUT); close(CLOCK);
Any help appreciated. Thanks, Stacy.

Replies are listed 'Best First'.
Re: Using map
by BrowserUk (Patriarch) on Oct 22, 2002 at 06:26 UTC

    map processes a list and returns a list, so your need to assign the list back to your @data array (or a new array).

    @data = map { #? data is skiped when plotted if($maxreject[$i]) { $_ = "?$_" if($_ > $maxclip); } if($minreject[$i]) { $_ = "?$_" if($_ < $minclip); } $i++; $_; ######### YOU ALSO NEED TO PASS THE VALUE THROUGH!! } @data;

    That said, a for loop might be a better choice, but it should work.

    Update: As I said that your loop could be done as a for, I thought I ought show what I mean. I don't fully understand your algorithm, but either of the following would be functionally equivalent to your inner loop and (I think) they are somwhat easier to understand. Your choice is yours of course.

    # as a for loop for (@data} { $_ = '?'.$_ if $maxreject[$i] && $_ > $maxclip or $minreject[$i++] && $_ < $minclip }; # or as a map, but different. @data = map{ $maxreject[$i] && $_ > $maxclip or $minreject[$i++] && $_ < $minclip ? '?'.$_ : $_ } @data;

    Cor! Like yer ring! ... HALO dammit! ... 'Ave it yer way! Hal-lo, Mister la-de-da. ... Like yer ring!
Re: Using map
by BrowserUk (Patriarch) on Oct 22, 2002 at 06:14 UTC

    map processes a list and returns a list, so you need to assign the list back to your @data array (or a new array).

    @data = map { #? data is skiped when plotted if($maxreject[$i]) { $_ = "?$_" if($_ > $maxclip); } if($minreject[$i]) { $_ = "?$_" if($_ < $minclip); } $i++; } @data;

    That said, a for loop might be a better choice, but it should work.


    Cor! Like yer ring! ... HALO dammit! ... 'Ave it yer way! Hal-lo, Mister la-de-da. ... Like yer ring!
      Thanks for the quick response! However, assigning @array = map {} @data produces the following in my data:
      07/01 09:09:57 0 1 2 3 4 5 07/01 09:14:56 0 1 2 3 4 5 07/01 09:19:58 0 1 2 3 4 5 07/01 09:24:58 0 1 2 3 4 5 07/01 09:29:58 0 1 2 3 4 5 07/01 09:34:58 0 1 2 3 4 5
      Hmm.

        Sorry! Take another look, I've updated the previous answer.

        With map, the value that gets passed out it the last value in the code block. In your case it was the $i++ expression, hence the counts you got. Add the new last line I indicate above and it should fix that. I didn't notice that the first time.

        I still think this is an iffy use of map though.


        Cor! Like yer ring! ... HALO dammit! ... 'Ave it yer way! Hal-lo, Mister la-de-da. ... Like yer ring!
Re: Using map
by Zaxo (Archbishop) on Oct 22, 2002 at 06:24 UTC

    Your map is in void context, it is not used for anything but a fancy loop. I think the logic of the @maxreject array is flawed, but I'm not sure what you're trying to accomplish with it.

    I suspect you want (split ' ') where you break a line into an array.

    Update: Ah, in that case, I'd keep an array of the column indexes to tag (supposing there may be more than one) and do this:

    my @tagthese = (4,5,6); # ... down in the read loop for (@data[@tagthese]) { $_ = '?' . $_ if $_ < $minclip or $_ > $maxclip; }

    After Compline,
    Zaxo

      The idea behind the @maxreject array is that is a user to rejects values associated with a column, they click a checkbox on the form and the value for that column becomes true. If the value is greater or less than a user-defined value, the value of the column is flagged.
      Stacy.
Re: Using map
by kabel (Chaplain) on Oct 22, 2002 at 07:39 UTC
    apart from the correct answers given:

    do use strict; but not in this way. it is quite - sorry, do not misunderstand - ridiculous seeing that you obviously copied the 11 characters into your posting.

    just get used to use it NOW IN YOUR SCRIPTS, not in this place ;)