La funzione map
fornisce un modo semplice per trasformare una
lista di valori in un'altra lista di valori. Di solito questa trasformazione ritorna lo stesso
numero di valori, anche se è sempre possibile generare una lista con un numero di valodi diverso.
Abbiamo visto che la funzione grep di Perl è una generalizzazione del medesimo comando UNIX. La funzione seleziona alcuni o tutti (o nessuno!) degli elementi dalla lista originale, e li ritorna intatti.
La funzione map
, invece, è utile quando si vogliono cambiare
i valori della lista originale.
La sintassi è simile. Basta passare alla funzione un blocco di codice ed una lista di valori: un array
o qualche altra espressione che ritorni una lista di valori.
Per ogni elemento della lista originale, il valore è copiato nella variabile $_
,
la variabile predefinita di Perl, ed il blocco
è eseguito. I valori risultanti sono passati alla lista risultante.
Uso di map per trasformazioni semplici
my @numbers = (1..5);
print "@numbers\n"; # 1 2 3 4 5
my @doubles = map {$_ * 2} @numbers;
print "@doubles\n"; # 2 4 6 8 10
Costruire tabelle di look-up veloci
Se abbiamo una lista di valori può capitare, durante l'esecuzione del codice, di voler controllare se un valore è compreso nella lista. Possiamo usare grep ogni volta, per cercare se il valore è nella lista. Possiamo anche usare la funzione any del package List::MoreUtils, ma può essere più leggibile e veloce usare una variabile hash per costruire una veloce tabella di look-up.
Possiamo creare una variabile hash una volta sola, dove per chiavi usiamo i valori della lista,
ed i corrispondenti valori sono qualunque cosa che valorizzi a true (quindi 1, "1", ma anche "52" o "Perl rocks!").
Possiamo usare questa variabile hash al posto della funzione grep
.
use Data::Dumper qw(Dumper);
my @names = qw(Foo Bar Baz);
my %is_invited = map {$_ => 1} @names;
my $visitor = <STDIN>;
chomp $visitor;
if ($is_invited{$visitor}) {
print "The visitor $visitor was invited\n";
}
print Dumper \%is_invited;
Questo è l'output della chiamata Dumper
:
$VAR1 = {
'Bar' => 1,
'Baz' => 1,
'Foo' => 1
};
Come anticipato, il valore che assegnamo agli elementi dell'hash non è importante, deve semplicemente essere valutato a true in una espressione.
Questa soluzione è interessante solo si accede spesso alla tabella di look-up e per
un grande set di valori (l'esatto significato di "grande" potrebbe dipendere dal vostro
sistema).
Altrimenti any
o anche grep
andranno bene lo stesso.
Come potete vedere in questo esempio, per ogni elemento nell'array originale,
map
ritorna 2 valori. Il valore originale e 1.
Il codice seguente:
my @names = qw(Foo Bar Baz);
my @invited = map {$_ => 1} @names;
print "@invited\n"
stamperà:
Foo 1 Bar 1 Baz 1
La freccia "grassa"
Nel caso ve lo state chiedendo il simbolo =>
è chiamato la fat arrow or fat comma. Praticamente
si comporta come una virgola regolare ,
con una eccezione che non è rilevante nel nostro caso. (Per ogni dettaglio
sul suo uso leggetevi l'articolo Perl hashes.)
Espressioni complesse in map
Potete dare in pasto a map istruzioni più complesse:
my @names = qw(Foo Bar Baz);
my @invited = map { $_ =~ /^F/ ? ($_ => 1) : () } @names;
print "@invited\n"
stamperà:
Foo 1
Nel blocco abbiamo un operatore ternario che ritorna o una coppia di valori come prima o una lista vuota. A quanto pare ammettiamo solo le persone il cui nome inizia con "F".
$_ =~ /^F/ ? ($_ => 1) : ()
perldoc
Per informazioni ulteriori ed un paio di casi strani, date una occhiata a perldoc -f map.