2009-02-22 19 views

Odpowiedz

24

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.

+1

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

+0

@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ę. –

2

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.

3

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.

+0

nie mapuje tak samo w kontekście skalarnym? –

+0

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

+0

dzięki za wyjaśnienie, że :) –

10

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().

4

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() 
0

Na przekór: grep podaje kontekst skalarny bloku, mapa podaje kontekst listy bloków. (I LISTA foreach BLOCK daje kontekst pustej ramki).

Powiązane problemy