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

Dear good monks, If I have two arrays, say
@a = (1,9,3,4,5,6,7,2,4,3) @b = (x,y,z,z,a,z,z,z,b,c)
I need to delete the all but the first corresponding characters in @a for multiple occurrences of 'z' so the new @a looks like
@anew =(1,9,3,5,6,4,3)
Many thanks in anticipation of suggestions. PS I should mention repetitions of any other character appart from 'z' are allowed.

Replies are listed 'Best First'.
Re: delete multiple occurrences
by BrowserUk (Patriarch) on Jan 13, 2009 at 05:45 UTC
      thanks for this, I forgot to mention repetitions of other characters in @b are allowed and should not be filtered. Only 'z' repetitions need filtering
Re: delete multiple occurrences
by davido (Cardinal) on Jan 13, 2009 at 07:05 UTC

    It's more fun with a regular expression! ;)

    use strict; use warnings; my @a = ( 1,9,3,4,5,6,7,2,4,3); my @b = qw/x y z z a z z z b c/; # Target: @anew =(1,9,3,5,6,4,3) my @anew = boil( \@a, \@b ); print "@anew\n"; sub boil { my ( $numbers, $letters ) = @_; my $pad = ''; $pad .= $letters->[$_] . $numbers->[$_] foreach 0 .. $#{$numbers}; { no warnings qw/uninitialized/; $pad =~ s/(?:z(.)(?:z.)+)|(?:.(.))/$1$2/g; } return split //, $pad; }

    I suspect the goal isn't "fun", so bear in mind that the RE approach is fragile if your input data deviates from the format you provided. For example, double-digit numerals will pretty much be the end of the fun unless the RE is modified to accommodate that contingency. But I couldn't resist the opportunity to play with it nevertheless.


    Dave

Re: delete multiple occurrences
by Arunbear (Prior) on Jan 13, 2009 at 08:40 UTC
    Yet another way:
    a = [ 1, 9, 3, 4, 5, 6, 7, 2, 4, 3 ] b = ['x', 'y', 'z', 'z', 'a', 'z', 'z', 'z', 'b', 'c'] anew = [] for i, t in enumerate(zip(a, b)): n, c = t if i > 0 and c == 'z' and c == b[i-1]: pass else: anew.append(n) print anew
    which prints:
    [1, 9, 3, 5, 6, 4, 3]
    ;-)
Re: delete multiple occurrences
by jwkrahn (Abbot) on Jan 13, 2009 at 06:32 UTC

    Another way to do it:

    $ perl -le' my @a = qw( 1 9 3 4 5 6 7 2 4 3 ); my @b = qw( x y z z a z z z b c ); my $char = "z"; my @anew; for my $i ( 0 .. $#b ) { if ( $b[ $i ] =~ ?^$char$? ) { push @anew, $a[ $i ]; } elsif ( $b[ $i ] =~ /^$char$/ ) { next; } else { push @anew, $a[ $i ]; reset; } } print "@anew"; ' 1 9 3 5 6 4 3
Re: delete multiple occurrences
by johngg (Canon) on Jan 13, 2009 at 11:11 UTC

    This uses an array slice greping the indices of @b that satisfy the criteria.

    use strict; use warnings; my @a = ( 1, 9, 3, 4, 5, 6, 7, 2, 4, 3 ); my @b = qw{ x y z z a z z z b c }; my @aNew = @a[ grep { ! $_ || $b[ $_ ] ne q{z} || $b[ $_ - 1 ] ne q{z} } 0 .. $#b ]; print qq{@aNew};

    The output.

    1 9 3 5 6 4 3

    I hope this is of interest.

    Cheers,

    JohnGG

Re: delete multiple occurrences
by gone2015 (Deacon) on Jan 13, 2009 at 09:25 UTC

    Or using grep:

    my $q = '' ; my $i = 0 ; @anew = grep { my $p = $q ; $q = $b[$i++] eq 'z' ; !($p && $q) } @a +;
    (having checked that the arrays @a and @b are the same length, at least).

Re: delete multiple occurrences
by holli (Abbot) on Jan 13, 2009 at 05:24 UTC
    untested:
    @anew = shrink(\@a, \@b); sub shrink { my %seen; my @ret; warn ("input arrays not the same length") unless scalar @{$_[0]} == scalar @{$_[1]}; for my $i ( 0..scalar @{$_[1]} ) { push @ret, $_[0]->[$i] unless $seen{$_[1]->[$i]}; $seen{$_[1]->[$i]} = 1; } return @ret; }


    holli, /regexed monk/
        Yes, I just realized I misread the problem. Doesn't matter. First post get XP that or that way ;)


        holli, /regexed monk/
Re: delete multiple occurrences
by repellent (Priest) on Jan 13, 2009 at 18:39 UTC
    my $i = -1; my $p = 0; my @anew = map { $i++; !(/^z$/ or $p = 0) || !$p++ ? $a[$i] : () } @b;
Re: delete multiple occurrences
by sanku (Beadle) on Jan 13, 2009 at 10:08 UTC
    hi, try out this one.
    @a = (1,9,3,4,5,6,7,2,4,3); @b = ("x","y","z","z","a","z","z","z","b","c"); @a=reverse(@a); @b=reverse(@b); foreach $l(0 .. scalar @a){ $next=$b[$l+1]; $next1=$b[$l+2]; if($next ne $b[$l]){ push(@c,$a[$l]); } } print reverse @c;