2010-03-28 10 views
10

Ho una struttura dati che è un hash che contiene un array di hash. Mi piacerebbe arrivare lì dentro e tirare fuori il primo hash che corrisponde a un valore che sto cercando. Ho provato questo:Perché lo spostamento di Perl si lamenta? Il tipo di arg 1 per lo spostamento deve essere array (non grep iterator). '?

my $result = shift grep {$_->{name} eq 'foo'} @{$hash_ref->{list}}; 

Ma che mi da questo errore: Type of arg 1 to shift must be array (not grep iterator). Ho riletto il perldoc per grep e penso che quello che sto facendo ha un senso. grep restituisce una lista, giusto? È nel contesto sbagliato?

Per ora utilizzerò una variabile temporanea, ma mi piacerebbe capire perché questo non funziona.

risposta

18

A list isn't an array.

my ($result) = grep {$_->{name} eq 'foo'} @{$hash_ref->{list}}; 

... dovrebbe fare il lavoro però. Prendi il ritorno da grep nel contesto dell'elenco, ma non assegna alcun valore diverso dal primo.

+5

Penso che andrò a scrivere "Una lista non è un array" 100 volte sulla mia lavagna. Grazie. – wes

+0

Ora c'è una risposta molto migliore per le FAQ: http://www.effectiveperlprogramming.com/blog/39 –

+0

@brian d foy - Quando vengono aggiornate le FAQ? (lo vedremo in un punto di rilascio di Perl 5 versione 10, o sarà nella versione 12?) – Quentin

17

Penso che un modo migliore per scrivere questo sarebbe questo:

use List::Util qw/first/; 

my $result = first { $_->{name} eq 'foo' } @{ $hash_ref->{list} }; 

Non solo sarà più chiaro quello che stai cercando di fare, sarà anche più veloce perché si fermerà grep l'array una volta trovato l'elemento corrispondente.

2

Un altro modo per farlo:

my $result = (grep {$_->{name} eq 'foo'} @{$hash_ref->{list}})[0]; 

Si noti che le graffe intorno al primo argomento di grep sono ridondanti in questo caso, in modo da poter evitare i costi di configurazione di blocco e teardown con

my $result = (grep $_->{name} eq 'foo', @{$hash_ref->{list}})[0]; 

“List value constructors” in perldata documenti abbonati alle liste:

A list value may also be subscripted like a normal array. You must put the list in parentheses to avoid ambiguity. For example:

# Stat returns list value. 
$time = (stat($file))[8]; 

# SYNTAX ERROR HERE. 
$time = stat($file)[8]; # OOPS, FORGOT PARENTHESES 

# Find a hex digit. 
$hexdigit = ('a','b','c','d','e','f')[$digit-10]; 

# A "reverse comma operator". 
return (pop(@foo),pop(@foo))[0]; 

Come ricordo, abbiamo questa funzione quando lo abbiamo suggerito in modo scherzoso con Randal Schwartz e Chip Salzenberg, che a quei tempi era un'appliance, l'ho implementata quella sera.

Aggiornamento: Un po 'di ricerca mostra la funzione che avevo in mente era $coderef->(@args). Il messaggio di commit registra anche la conversazione!

Problemi correlati