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

Hello Map-Happy Monks,

I thought I could extract a subset fom a list by doing this:

my @allFruit = qw/apple apricot banana coconut/; my @someFruit = map { if ($_ =~ m/^[ap]/) { $_;} } @allFruit; print "no. of some fruit: " . scalar(@someFruit) . "\n"; print "some fruit: " . join('*',@someFruit) . "\n";

This however produces this output:

no. of some fruit: 4 some fruit: apple*apricot**

rather than

no. of some fruit: 2 some fruit: apple*apricot

which was what I wanted.

What would be the best way of doing such extraction?

loris

Replies are listed 'Best First'.
Re: Extracting subset from list: map unsuitable?
by gaal (Parson) on Apr 13, 2005 at 07:37 UTC
    @someFruit = grep /^[ap]/, @allFruit;
Re: Extracting subset from list: map unsuitable?
by borisz (Canon) on Apr 13, 2005 at 07:39 UTC
    You should use grep.
    my @allFruit = qw/apple apricot banana coconut/; my @someFruit = grep { m/^[ap]/ } @allFruit; print "no. of some fruit: " . scalar(@someFruit) . "\n"; print "some fruit: " . join('*',@someFruit) . "\n"; __OUTPUT__ no. of some fruit: 2 some fruit: apple*apricot
    Boris

      Thanks to you and gaal. I knew it must be something obvious.

      loris

Re: Extracting subset from list: map unsuitable?
by Zaxo (Archbishop) on Apr 13, 2005 at 07:49 UTC

    As you've heard, grep is best. You could use map instead with this kind of construction: my @someFruit = map { /^[ap]/ ? $_ : ();} } @allFruit; The ternary picks either the array element or the empty list, depending on the match test result. The empty list does not create a new array element where undef would.

    It would be silly to do this for your particular problem when grep fits so well, but it can be very handy for more complicated situations.

    After Compline,
    Zaxo

Re: Extracting subset from list: map unsuitable?
by bart (Canon) on Apr 13, 2005 at 07:56 UTC
    You don't ave an else part. Use an empty list, and it'll work.
    my @someFruit = map { if ($_ =~ m/^[ap]/) { $_;} else { (); } } @allFr +uit;
    I now get:
    no. of some fruit: 2
    some fruit: apple*apricot
    
    Just to show you that it can be made to work. I'm not sure what is inserted in your version, I would have though of undef, but I get no warnings, so likely it's a boolean false (0 as number and "" as string), same value as !1 returns.

    For this particular application, it would be wiser to use grep, but you could have used ? : too. And there's no need for the $_ =~. (Or the m.)

    my @someFruit = map { m/^[ap]/ ? $_ : () } @allFruit;
    my @someFruit = grep { m/^[ap]/ } @allFruit;
Re: Extracting subset from list: map unsuitable?
by rev_1318 (Chaplain) on Apr 13, 2005 at 07:46 UTC
    As the others pointed out, use grep.

    map evaluates the expression for each element of the list and returns it's result. In your case, since 2 elements of @allFruit do not fullfill the if-statement, for these undef is returned, so you still get 4 elements.

    see grep and map for the diferences between the two.

    Paul