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

I have an array, and I need in easy way to reduce it on the base of it's entries. I need to loop on the array and if the current entry equals a specific items, I want to move this entry out of the array, example:
my @array = qw(dog cat cow horse donkey chicken); my @items = qw(cat donkey); # after the manipulation I'd like to have: @array == qw(dog cow horse chicken);
I'm sure that's not a hard task (looping and looping), but I'm also sure that I can do it more easily using perl power (that I'm not quite control it yet).
anyone?

Thanks.

Hotshot

Replies are listed 'Best First'.
Re: Reducing array
by jmcnamara (Monsignor) on May 09, 2002 at 09:35 UTC

    It would be better to store the items that you don't want in a hash. Then you could do something like this using grep:
    #!/usr/bin/perl -w use strict; my @array = qw(dog cat cow horse donkey chicken); my %items = (cat => 1, donkey =>1); @array = grep {not exists $items{$_}} @array; print "@array\n"; __END__ prints: dog cow horse chicken

    --
    John.

Re: Reducing array
by tachyon (Chancellor) on May 09, 2002 at 09:52 UTC

    Here is a neat trick using a specially constructed reg-ex that matches /this|that|the|other|bit/ and then the ever invaluable grep().

    my @array = qw(dog cat cow horse donkey chicken); my @items = qw(cat donkey); # make our magical reg-ex that will match what we don't want # note we must quotmeta literal strings before we bung em in a reg-ex my $re = join '|', map { quotemeta } @items; my $re = qr/$re/; # use qr// to compile our reg-ex my @fixed = grep { ! /$re/ } @array; # grep the results out print "@fixed" ;

    cheers

    tachyon

    s&&rsenoyhcatreve&&&s&n.+t&"$'$`$\"$\&"&ee&&y&srve&&d&&print

Re: Reducing array
by hopes (Friar) on May 09, 2002 at 11:56 UTC
    Another way to do the same (from the FAQ)
    perlfaq4
    How do I compute the difference of two arrays?
    How do I compute the intersection of two arrays?
    Use a hash. Here's code to do both and more. It assumes that each elem +ent is unique in a given array: @union = @intersection = @difference = (); %count = (); foreach $element (@array1, @array2) { $count{$element}++ } foreach $element (keys %count) { push @union, $element; push @{ $count{$element} > 1 ? \@intersection : \@difference } +, $element; } Note that this is the symmetric difference, that is, all elements in e +ither A or in B but not in both. Think of it as an xor operation.


    Hopes
    $_=$,=q,\,@4O,,s,^$,$\,,s,s,^,b9,s, $_^=q,$\^-]!,,print
(cLive ;-) Re: Reducing array
by cLive ;-) (Prior) on May 09, 2002 at 10:03 UTC
    This got me thinking - it's one of those timtowtdi thingies, but I thought this solution was quite nice - to begin with - look at this
    # First, but @items into a hash instead though... my @array = qw(dog cat cow horse donkey chicken); my %items = qw(cat 1 donkey 1); # this is weird.. if this is true print "\$array[-4] = $array[-4]\n"; for (1..@array) { splice(@array, -$_, 1) if $items{ $array[-$_] }; } # and this is true print "\$array[-4] = $array[-4]\n"; # how come this is right??? print join ', ',@array, "\n";
    And then I thought about it. Hang on. The array's getting spliced each time a match is made, so an index of -$_ would skip elements (ie $array[-4] before is 'cow', after, it's 'dog', which is expected, but... Weird thing is, it doesn't look like it should work. Anyone got any idea why this works when I think it shouldn't???

    err

    cLive ;-)


      Anyone got any idea why this works...

      It doesn't work. You were just lucky. :-) Try:

      my %items = qw(horse 1 donkey 1); .. Prints: dog cat cow horse chicke

      --
      John.

Re: Reducing array
by educated_foo (Vicar) on May 09, 2002 at 15:29 UTC
    I can't believe no one's added this yet.
    use strict; use Quantum::Superpositions; my @a = qw(cat dog monkey); my @b = qw(cat dog); print map { $_ eq any(@b) ? () : ($_) } @a;
    /s