Guida Perl: come trasformare un array con map.

Creato il 08 settembre 2014 da Hugor @msdiaz61

Trasformare un array con map

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