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

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

I want to apply a F T T F repeating pattern as a filter to an array or list. Here is what I came up with:

$i = 0; @result = grep { $i = 0 unless ($i<4); $i++%3 ? 1 : 0; } 0..12

@result = 1,2,5,6,9,10

It works but looks clunky. Any more elegant options?

But God demonstrates His own love toward us, in that while we were yet sinners, Christ died for us. Romans 5:8 (NASB)

Replies are listed 'Best First'.
Re: Grep Pattern
by hdb (Monsignor) on Dec 12, 2018 at 14:59 UTC

    You could pre-program your pattern, which imho is elegant and transparent and easily adaptable to more complex situations.

    @pat = ( 0, 1, 1, 0 ); $i = 0; @result = grep { $pat[ $i++ % 4 ] } 0..12;

    I guess you could also replace "4" with "@pat" to make it even more general.

      That's the approach I would recommend as well. But you kinda messed up on the implementation.
      my @pat = ( 0, 1, 1, 0 ); my @result = grep { $pat[ $_ % @pat ] } 0..12;
        > But you kinda messed up on the implementation.

        Not really, you are filtering the sample input, hdb is filtering any input by a "repeating pattern".

        update
        DB<10> @pat = ( 0, 1, 1, 0 ); DB<11> x $i=0;grep { $pat[ $i++ % 4 ] } a..l; 0 'b' 1 'c' 2 'f' 3 'g' 4 'j' 5 'k' DB<12>

        Cheers Rolf
        (addicted to the Perl Programming Language :)
        Wikisyntax for the Monastery FootballPerl is like chess, only without the dice

        that's elegant...

        $ ./1.grep_pattern.pl result is 1 2 5 6 9 10 $ cat 1.grep_pattern.pl #!/usr/bin/perl -w use 5.011; my @pat = ( 0, 1, 1, 0 ); my @result = grep { $pat[ $_ % @pat ] } 0..12; say "result is @result"; __END__ $
Re: Grep Pattern
by Eily (Monsignor) on Dec 12, 2018 at 14:39 UTC

    Having a TTFFTTFF... pattern is quite easy:

    DB<11> $i = 0; say for grep { $i++ % 4 < 2 } 0..12 0 1 4 5 8 9 12
    And starting at the fourth value in the pattern just means your start at the fourth value of $i:
    DB<12> $i = 3; say for grep { $i++ % 4 < 2 } 0..12 1 2 5 6 9 10

Re: Grep Pattern
by tybalt89 (Parson) on Dec 12, 2018 at 14:52 UTC
    #!/usr/bin/perl -l # https://perlmonks.org/?node_id=1227147 use strict; use warnings; my $pattern = '011'; my @result = grep $pattern =~ /./g && $&, 0..12; local $, = ','; print @result;
      What if the last element in the pattern is T, not F?

      ($q=q:Sq=~/;[c](.)(.)/;chr(-||-|5+lengthSq)`"S|oS2"`map{chr |+ord }map{substrSq`S_+|`|}3E|-|`7**2-3:)=~y+S|`+$1,++print+eval$q,q,a,

        Just invert the pattern and the test :)

        #!/usr/bin/perl -l # https://perlmonks.org/?node_id=1227147 use strict; use warnings; my $pattern = '011'; my @result = grep !($pattern =~ /./g && $&), 0..12; local $, = ','; print @result;

        Outputs:

        0,3,4,7,8,11,12
        Here I reset 'pos' when match approaches the end of the pattern, allowing second regex always match:
        #!/usr/bin/perl # https://perlmonks.org/?node_id=1227147 use warnings; use strict; my $pattern = 'FTTF'; my @result = grep { $pattern =~ /(?!$)/g; $pattern =~ /./g; $& eq 'T' } 0 .. 12; print "@result\n";
      Similar idea:
      #!/usr/bin/perl # https://perlmonks.org/?node_id=1227147 use warnings; use strict; my $pattern = 'FTTF'; my $repeated_pattern = $pattern x ( 1 + ( map $_, 0 .. 12 ) / length $ +pattern ); my @result = grep { $repeated_pattern =~ /./g; $& eq 'T' } 0 .. 12; print $repeated_pattern, "\n"; print "@result\n";
Re: Grep Pattern
by rsFalse (Friar) on Dec 15, 2018 at 20:06 UTC
    Another one, with rotating:
    #!/usr/bin/perl # https://perlmonks.org/?node_id=1227147 use warnings; use strict; my $short_pattern = 'FTTF'; my @result = grep { $short_pattern = ( chop $short_pattern ) . $short_patt +ern; $short_pattern ge 'T' } 0 .. 12; print "@result\n";
    P.S. note a wrong rotation direction. So, the pattern should be reversed before, if it's not a palindrome.
Re: Grep Pattern
by LanX (Archbishop) on Dec 20, 2018 at 14:34 UTC
    slightly cheating ;-)

    DB<33> x @a=(0,1,1); grep { (each @a)[1] } A..L 0 'B' 1 'C' 2 'F' 3 'G' 4 'J' 5 'K'

    here the general case w/o cheating:

    (like when the filter cycle ends with a 1 you'd need)

    DB<34> x @a=(0,0,1,1); grep { (each @a)[1] // (each @a)[1] } A..L 0 'C' 1 'D' 2 'G' 3 'H' 4 'K' 5 'L'

    Cheers Rolf
    (addicted to the Perl Programming Language :)
    Wikisyntax for the Monastery FootballPerl is like chess, only without the dice