В чем разница между grep и map в Perl? - PullRequest
14 голосов
/ 22 февраля 2009

В Perl grep и map принимают выражение и список и оценивают выражение для каждого элемента списка.

В чем разница между двумя?

Ответы [ 6 ]

25 голосов
/ 22 февраля 2009

grep возвращает те элементы исходного списка, которые соответствуют выражению, тогда как map возвращает результат выражения, примененного к каждому элементу исходного списка.

$ 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

Первый пример печатает все нечетные элементы списка, а второй пример печатает 0 или 1 в зависимости от того, является ли соответствующий элемент нечетным или нет.

10 голосов
/ 23 февраля 2009

Я считаю, что полезно подумать о grep() и map() в их наиболее общем виде:

grep {BLOCK} LIST   
map  {BLOCK} LIST

grep() - это фильтр: он возвращает подмножество элементов из LIST, для которых BLOCK возвращает true.

map() - это функция отображения: отправьте значение из LIST в BLOCK, и BLOCK вернет список из 0 или более значений; объединенный набор всех этих вызовов BLOCK будет окончательным списком, возвращаемым map().

4 голосов
/ 26 февраля 2009

map применяет функцию ко всем элементам в списке и возвращает результат.

grep возвращает все элементы в списке, которые имеют значение true, когда к ним применяется функция.

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()
3 голосов
/ 22 февраля 2009

Еще одна вещь, связанная с grep: в скалярном контексте он сообщает, сколько элементов он нашел. Это может быть полезно, если вам не нужен второй список, но вы хотите знать, сколько элементов определенного вида.

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

Редактировать: Поскольку ОП задан в комментарии, я должен сказать, что вы можете использовать map в скалярном контексте таким же образом. Дело не в том, что grep - единственный из двух, кто может это сделать, но в том, что иногда бывает полезно сделать это с grep.

2 голосов
/ 22 февраля 2009

Думайте о grep как о карте с фильтром. Карта повторяется и дает возможность что-то делать с каждым элементом. Например, эти две строки эквивалентны:

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

Аналогично, эти два эквивалента:

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

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

grep предоставляет возможность вставлять условные выражения и поэтому становится фильтром.

0 голосов
/ 19 мая 2011

Facetiously: grep задает свой скалярный контекст блока, map - контекст списка блоков. (И BLOCK foreach LIST дает контекст пустого блока.)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...