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

Hello fellow monks, I have the following question. This example is kind of contrived; I am doing this to test out an algorithm for a larger project. I have the following in an array:
apple chocolate ice-cream apple chocolate pie apple chocolate custard apple caramel ice-cream apple caramel pie apple caramel custard apple vanilla ice-cream apple vanilla pie apple vanilla custard banana chocolate ice-cream banana chocolate pie banana chocolate custard banana caramel ice-cream banana caramel pie banana caramel custard banana vanilla ice-cream banana vanilla pie banana vanilla custard orange chocolate ice-cream orange chocolate pie orange chocolate custard orange caramel ice-cream orange caramel pie orange caramel custard orange vanilla ice-cream orange vanilla pie orange vanilla custard
I have another array with the following:
apple chocolate pie apple caramel custard banana caramel ice-cream orange vanilla pie
What I'm trying to do is remove all items present in the second array, from the first array. To do that, I have this line of code:

map {@yum = grep {!/$_/} @yum;} @bad;

@yum is the first array and @bad is the second. The problem is that when I run this code, @yum is empty. However, when the equivalent statements produced by the map are run, I get the desired result.
@yum = grep {!/apple chocolate pie/} @yum; @yum = grep {!/apple caramel custard/} @yum; @yum = grep {!/banana caramel ice-cream/} @yum; @yum = grep {!/orange vanilla pie/} @yum;
Why is this happening?

Replies are listed 'Best First'.
Re: Map not working as expected.
by chromatic (Archbishop) on May 04, 2007 at 20:19 UTC

    This line is odd:

    map {@yum = grep {!/$_/} @yum;} @bad;

    What do you expect $_ to represent in the grep block? If you want it to represent the elements of @bad, then you need to copy it to a lexical, because inside the grep block, it represents each element of @yum in turn.

    However, this is not really an appropriate use of map, and not in the least because it doesn't work. Use map when you want to transform one list to another list.

    To exclude elements, use a hash (and presumably a grep):

    # here's a list transform, from a list into a list of pairs my %bad = map { $_ => undef } @bad; my @good_yum = grep { not $bad{$_} } @yum;
Re: Map not working as expected.
by shigetsu (Hermit) on May 04, 2007 at 21:13 UTC
    I second chromatic's advice. But for the sake of completeness, here's one using List::MoreUtils::none():
    @yum = map { my $yum = $_; (none { /$yum/ } @bad) ? $yum : () } @yum;
    It's a bit cryptic, but it does its job.
Re: Map not working as expected.
by pileofrogs (Priest) on May 04, 2007 at 21:24 UTC

    I think the perl interpreter won't let you classify as "bad" anything as obviously yummy as an apple chocolate pie.:)

    <ducks head>

    -Pileofrogs

      I like BBQ frog legs :=)