At 5:59 AM +0200 6/22/01, Louis Pouzin wrote:
>On Tue, 19 Jun 2001 15:25:56 +0200, Bart Lateur wrote:
>>On Tue, 19 Jun 2001 03:09:54 +0200 (MEST), Louis Pouzin wrote:
>
>>>I want to test and remove one element of an array when it is '-s'.

[snip]

>>  * But my [Bart's] favourite is to use grep():
>
>>      @ARGV = grep { $_ ne '-s' } @ARGV;
>
>>Caveat: all untested. How unresponsible. And you have to put the 
>>test for whether '-s' was there, in it somewhere.
>
>It's great. Here is the complete script:
>
>       #!/usr/local/bin/perl -w
>       @ARGV = (2,'-s','fil'); my $sel = 0;
>       grep { /^-s$/o && ($sel = 1) } @ARGV;
>       @ARGV = grep { $_ ne '-s' } @ARGV;
>       print "$sel, @ARGV \n";
>       __END__
>
>Could the 2 grep's be somehow merged ?

Yes, in the sense that the grep operation may be arbitrarily complex 
as long as it returns a Perlish true or false value for each element 
of the list being processed.

@output = grep { #grep operation#  } @input;

Each element of the input list, in this example stored in @input, is 
passed in to the grep operation as Perl's magic 'it' variable, $_.. 
If the grep operation returns a true value, that list element is 
passed to the output list, in @output here; if false, no value is 
passed.

my @input = (2,4,6,8);
my @output = grep { $_ > 5 } @input;
# @output is now (6,8)

Check this out:

#!perl -lw  -- multi-statement grep operation

  my @input = (1,3,8,3,5,4,2,7,5,6);
  my (@output, @double_output, @bad_ones);
  @output = grep {
    my $input_item = $_;       # $_ is each element of @input, in order.
    my $truth = $input_item % 2;                # Example truth test (modulo)
    $truth                                                        # 
Compound truth statement that also
         and push @double_output => $input_item * 2    # populates 
@double_output
            or push @bad_ones =>  $input_item and 0;      #   or @bad_ones
  } @input;

  print join( ' ' => @output);
  print join( ' ' => @double_output);
  print join( ' ' => @bad_ones);
  __END__

1 3 3 5 7 5
2 6 6 10 14 10
8 4 2 6

Note that the grep operation may do other things while getting to 
returning a truth value, like setting values of other variables in 
its scope. This is what your first grep statement above is doing:
     grep { /^-s$/o && ($sel = 1) } @ARGV;
This looks at each element of @ARGV, and if an element matches 
/^-s$/o, it sets $sel to 1, and the complete operation will return a 
true value.

A true value means that this element of @ARGV would be output, but 
the script provides no list to receive it. This is what is known as 
Using Grep in a Void Context. You won't be arrested if you do it, but 
just keep in mind that the grep statement above doesn't change 
@ARGV's elements or filter them into a smaller list. So all that 
would happen is that $sel will be switched from 0 to 1 if some member 
of @ARGV matches /^-s$/o. Also, in the script above there's nothing 
that resets $sel, so as soon as it's been set to 1 once, it will stay 
1.

I think I missed the earlier discussion of what you're trying to do 
here, but is this what it was?

If that is what you want, then to answer your question above,  you 
might use something like:

@ARGV = grep {
    /^-s$/o and $sel = 1;   # whatever this is for.
    $_ ne '-s'                       # truth test
} @ARGV;

# Or:

  @ARGV = grep {/^-s$/o and $sel = 1; $_ ne '-s' } @ARGV;  # Same thing

HTH

1;

Reply via email to