W języku Perl oba grep
i map
pobierają wyrażenie i listę i oceniają wyrażenie dla każdego elementu listy.Jaka jest różnica między grep i mapą w Perlu?
Jaka jest różnica między tymi dwoma?
W języku Perl oba grep
i map
pobierają wyrażenie i listę i oceniają wyrażenie dla każdego elementu listy.Jaka jest różnica między grep i mapą w Perlu?
Jaka jest różnica między tymi dwoma?
grep
zwraca te elementy z oryginalnej listy, które pasują do wyrażenia, podczas gdy map
zwraca wynik wyrażenia zastosowanego do każdego elementu oryginalnej listy.
$ 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
Pierwszy przykład drukuje nieparzyste elementy na liście, podczas gdy drugi przykład drukuje 0 lub 1 zależnie od tego, czy odpowiedni element jest nieparzysty, czy nie.
Pomyśl o grep jako mapie z filtrem. mapa iteruje i daje możliwość zrobienia czegoś z każdym przedmiotem. Przykładowo te dwie linie są równoważne
my @copy = @original;
my @copy = map {$_} @original;
Podobnie, te dwa są równoważne
my @copy = grep {-f $_} @original;
@copy =();
for (@original)
{
push @copy, $_ if -f $_;
}
grep umożliwia wstawianie warunkowego, a więc staje się filtra.
Jedna inna rzecz o grep
: w kontekście skalarnym informuje, ile znalezionych elementów. Może to być przydatne, jeśli naprawdę nie chcesz drugiej listy, ale chcesz wiedzieć, ile pozycji danego rodzaju istnieje.
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
Edycja: Ponieważ PO zapytał w komentarzu, powinienem powiedzieć, że można użyć map
w kontekście skalarnym w ten sam sposób. Nie chodzi o to, że grep
jest jedynym z dwóch, który może to zrobić, ale czasami przydaje się to przy pomocy grep
.
nie mapuje tak samo w kontekście skalarnym? –
Tak. Nie chciałem sugerować, że tylko grep to robi - tylko, że jest to fajna funkcja, której ludzie czasami nie znają. (Nie mogę też myśleć o przypadku, w którym chciałbym użyć mapy w kontekście skalarnym). – Telemachus
dzięki za wyjaśnienie, że :) –
Uważam, że warto jest pomyśleć pomyśleć o grep()
i map()
w swojej najbardziej ogólnej postaci:
grep {BLOCK} LIST
map {BLOCK} LIST
grep()
jest filtr: zwraca podzbiór przedmiotów z listy, dla którego BLOCK zwraca wartość true.
map()
jest funkcją mapowania: wyślij wartość z LISTY do BLOKU, a BLOK zwraca listę 0 lub więcej wartości; połączony zestaw wszystkich tych wywołań do BLOCK będzie ostateczną listą zwróconą przez map()
.
map
stosuje funkcję do wszystkich elementów na liście i zwraca wynik.
grep
zwraca wszystkie elementy z listy, które mają wartość true, gdy funkcja jest do nich stosowana.
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()
Na przekór: grep podaje kontekst skalarny bloku, mapa podaje kontekst listy bloków. (I LISTA foreach BLOCK daje kontekst pustej ramki).
Dodatkowo, mapowanie pozwala na mapowanie jeden-do-wielu, więc jego wyrażenie jest w kontekście listy, a nie skalarnym kontekście wyrażenia grep. – ysth
@ysth: To prawda.Chciałem powiedzieć coś o mapie, zwracając zawsze tę samą liczbę elementów, co argument listy, ale potem przypomniałem sobie, że wyrażenie może zwrócić nie więcej niż jeden element jako listę. –