Какая разница между grep и картой в Perl?
В Perl оба grep
и map
принимают выражение и список и оценивают выражение для каждого элемента списка.
В чем разница между двумя?
Ответы
Ответ 1
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 в зависимости от того, является ли соответствующий элемент нечетным или нет.
Ответ 2
Я считаю, что полезно подумать о grep()
и map()
в их наиболее общей форме:
grep {BLOCK} LIST
map {BLOCK} LIST
grep()
- это фильтр: он возвращает подмножество элементов из списка, для которого BLOCK возвращает true.
map()
- это функция отображения: отправьте значение из LIST в BLOCK, а BLOCK возвращает список из 0 или более значений; объединенный набор всех этих вызовов в BLOCK будет конечным списком, возвращаемым map()
.
Ответ 3
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 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()
Ответ 4
Еще одна вещь о 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
.
Ответ 5
Подумайте о grep как о карте с фильтром. map iterates и дает возможность сделать что-то с каждым элементом. Например, эти две строки эквивалентны:
my @copy = @original;
my @copy = map {$_} @original;
Аналогично, эти два эквивалентны:
my @copy = grep {-f $_} @original;
@copy = ();
for (@original)
{
push @copy, $_ if -f $_;
}
grep предоставляет возможность вставлять условное выражение и, следовательно, становится фильтром.
Ответ 6
Честно говоря: grep дает свой скалярный контекст блока, карта дает свой контекст списка блоков. (И BLOCK foreach LIST дает свой контекст пустоты блока.)