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 b
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()
.
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.
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.
Facetiously: grep gives its block scalar context, map gives its block list context. (And BLOCK foreach LIST gives its block void context.)
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
.
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()