Nathan Fellman
Nathan Fellman

Reputation: 127578

What's the difference between grep and map in Perl?

In Perl both grep and map take an expression and a list, and evaluate the expression for each element of the list.

What is the difference between the two?

Upvotes: 14

Views: 14184

Answers (6)

JDrago
JDrago

Reputation: 2099

map applies a function to all elements in a list and returns the result.

grep returns all elements in a list that evaluate to true when a function is applied to them.

my %fruits = (
  banana => {
    color => 'yellow',
    price => 0.79,
    grams => 200
  },
  cherry => {
    color => 'red',
    price => 0.02,
    grams => 10
  },
  orange => {
    color => 'orange',
    price => 1.00,
    grams => 225
  }
);

my %red_fruits = map { $_ => $fruits{$_} }
                   grep { $fruits{$_}->{color} eq 'red' }
                     keys(%fruits);

my @prices = map { $fruits{$_}->{price} } keys(%fruits);
my @colors = map { $fruits{$_}->{color} } keys(%fruits);
my @grams  = map { $fruits{$_}->{grams} } keys(%fruits);

# Print each fruit's name sorted by price lowest to highest:
foreach( sort { $fruits{$a}->{price} <=> $fruits{$b}->{price}} keys(%fruits) )
{
  print "$_ costs $fruits{$_}->{price} each\n";
}# end foreach()

Upvotes: 4

ysth
ysth

Reputation: 98398

Facetiously: grep gives its block scalar context, map gives its block list context. (And BLOCK foreach LIST gives its block void context.)

Upvotes: 0

Greg Hewgill
Greg Hewgill

Reputation: 994231

grep returns those elements of the original list that match the expression, while map returns the result of the expression applied to each element of the original list.

$ perl -le 'print join " ", grep $_ & 1, (1, 2, 3, 4, 5)'
1 3 5
$ perl -le 'print join " ", map $_ & 1, (1, 2, 3, 4, 5)'
1 0 1 0 1

The first example prints all the odd elements of the list, while the second example prints a 0 or 1 depending on whether the corresponding element is odd or not.

Upvotes: 26

FMc
FMc

Reputation: 42421

I find that it's helpful to think think about grep() and map() in their most general form:

grep {BLOCK} LIST   
map  {BLOCK} LIST

grep() is a filter: it returns the subset of items from LIST for which BLOCK returns true.

map() is a mapping function: send a value from LIST into BLOCK, and BLOCK returns a list of 0 or more values; the combined set of all of those calls to BLOCK will be the ultimate list returned by map().

Upvotes: 10

Telemachus
Telemachus

Reputation: 19715

One other thing about grep: in a scalar context it tells you how many items it found. This can be useful if you don't really want a second list, but you do want to know how many items of a certain kind there are.

my @numbers = qw/1 2 3 4 5 6/;

my @odd_numbers  = grep { $_ & 1 } @numbers; # grep returns (1, 3, 5)

my $how_many_odd = grep { $_ & 1 } @numbers; # grep returns 3

Edit: Since the OP asked in a comment, I should say that you can use map in a scalar context in the same way. The point wasn't that grep is the only one of the two that can do this, but that it sometimes comes in handy to do this with grep.

Upvotes: 3

Paul Beckingham
Paul Beckingham

Reputation: 14915

Think of grep as map with a filter. map iterates and provides an opportunity to do something with every item. For example these two lines are equivalent:

my @copy = @original;
my @copy = map {$_} @original;

Similarly, these two are equivalent:

my @copy = grep {-f $_} @original;

@copy = ();
for (@original)
{
  push @copy, $_ if -f $_;
}

grep provides the ability to insert a conditional, and therefore becomes a filter.

Upvotes: 2

Related Questions