in reply to flip-flop operator and sequence number

foreach (grep { not (/start/../stop/) =~ /^1?$|E/ } @data) { .. }

-- Randal L. Schwartz, Perl hacker

Replies are listed 'Best First'.
Re: Re: flip-flop operator and sequence number
by bwana147 (Pilgrim) on Jun 28, 2001 at 18:38 UTC

    Cool... And how about this one?

    foreach (sub {pop;shift;@_}->(grep /start/../stop/, @data) ) { ... }

    Sorry, just kidding :-)

    UPDATE: taking Abigail and John M. Dlugosz's remarks into account, the original post wanted to stop after the first occurence of 'stop'. I guess we should then be using ?? instead of // to prevent matching more than once.

    foreach (sub {pop;shift;@_}->(grep ?start?..?stop?, @data) ) { ... }

    --bwana147

      That code doesn't do the same.
      #!/opt/perl/bin/perl -wl use strict; my @data = qw /foo start bar baz stop qux start quux stop fuzzle/; foreach (grep /start/ .. /stop/, @data) { next if /start/ || /stop/; print } print "----"; foreach (sub {pop; shift; @_} -> (grep /start/ .. /stop/, @data)) { print; } __END__ bar baz quux ---- bar baz stop start quux
      You are losing the boundaries of the flip-flop operator, and use the boundaries of grep. But those boundary events are not necessarely the same.

      -- Abigail

        That's a good point. But your code is not the same either, since his original said last not next. He was stopping after the first group and ignoring a subsequent /start/.
      I love it! Using the sub{}->() idiom you can modify a list in-place without using a temporary. Your code does the same as:
      my @temp= grep /start/../stop/, @data; pop @temp; shift @temp; foreach (@temp) { ... }
      right?

      —John

        Er, actually, I feel like a hobbit being caught red handed meddling in the affairs of wizards, which are, as everybody knows, subtle and quick to anger.

        I tried and fiddle a bit with this and it's somewhat interesting. @_ is not itself aliased with the list of arguments. But each element of @_ is individually aliased with each argument. That means that you can't change the list itself (i.e. the number of its elements), but you can the values of each element. If I do:

        sub { pop; shift; }->(@array);

        It'll leave @array unharmed. OTOH, if I do:

        sub { $_[0] = 'whatever' }->(@array);

        It will change the first element of @array. You can combine both (although I would not recommend it):

        sub { shift; $_[0] = 'whatever' }->(@array); # changes the *second* element of @array

        --bwana147

Re: Re: flip-flop operator and sequence number
by mattr (Curate) on Jun 28, 2001 at 19:03 UTC
    .. not being able to do, reduced to nitpicking. Sorry your answer was so beautiful I studied it but.. perl -e '@data=qw(1 2 3 4 5 6 7 8 9 10 11); foreach (grep {not (/1/../3/) =~ /^1?$|E/ } @data) { print "o> $_\n"; } '
    prints
    o> 2
    o> 11

    I hope I'm wrong..

      Thats looks like the correct output to me. What were you expecting to see?

      Update: Ok. Getting downvotes, so perhaps I'll be a little clearer.

      Your array contains the numbers from 1 to 11. Your flip-flop condition is /1/ .. /3/. These are regular expressions and match if the values they are matched against contain this string in any position. Obviously it switches on when it gets to 1 and switches off when it gets to three. It then switches on again when it gets to 10. It would have switched off again had your array gone up to 13.

      The problem is therefore not with merlyn's algorithm, but with your implementation of it :)

      --
      <http://www.dave.org.uk>

      Perl Training in the UK <http://www.iterative-software.com>

Re: Re: flip-flop operator and sequence number
by iakobski (Pilgrim) on Jun 28, 2001 at 19:13 UTC
    mattr is right, merlyn's solution does not work.

    But this modification does:

    foreach ( grep { (/start/../stop/) !~ /^1?$|E/} @arry ){ #... }
    I looked a bit further, and what is coming out of the (/start/../stop/) is the sequence number...until you put the not in front of it. Then it just yields blank or 1!

    Any ideas why? Is it being evaluated in list context? Why does the not have any influence on the context?

    -- iakobski

      Uh, it is working. The start match is /1/, which also triggers on "10". So the output is:
      1 start - don't show 2 in - show 3 end - don't show 4 out 5 out 6 out 7 out 8 out 9 out 10 start - don't show 11 in - show
      It's exactly right. My solution works fine, no need to modify it.

      -- Randal L. Schwartz, Perl hacker

        What merlyn says is true enough, although there may be some confusion depending on what version of Perl you run merlyn's example with:

        [danger:jandrew:~]$ cat blah.pl #!/usr/bin/perl -w use strict; my @data = qw/one start two three stop four/; foreach (grep {not (/^start/../^stop/) =~ /^1?$|E/ } @data) { print "o> $_\n"; } [danger:jandrew:~]$ perl5.00503 blah.pl o> two o> three [danger:jandrew:~]$ perl5.6.1 blah.pl o> one o> start o> two o> three o> stop o> four

        Because, in 5.6+, the not operator with parens acts like a function (returns the negation of what's in the parens), so you'd want another set of parens to properly delimit what we want to negate (or use a unary +):

        my @data = qw/one start two three stop four/; foreach (grep {not ((/^start/../^stop/) =~ /^1?$|E/) } @data) { print "o> $_\n"; } # or: my @data = qw/one start two three stop four/; foreach (grep {not +(/^start/../^stop/) =~ /^1?$|E/ } @data) { print "o> $_\n"; }
      not puts things in a boolean context, either true or false. False is 0 and true is anything else (in numerical context at least), by convention we use 0 and 1 as false and true when we aren't concerned about data, just truthfulnes.

      The 15 year old, freshman programmer,
      Stephen Rawls

      That's a good observation on what not does.

      But, the binding operator =~ has a higher order of precidence, so the not applies to the result of the match, not to the left hand side being matched.

      —John