2010-10-10 13 views
6

Ho un iteratore con questa interfaccia: $ hit-> next_hspQual è il modo più elegante in Perl di espandere un iteratore in una lista?

L'implementazione corrente di listify è:

my @list; 
while (my $hsp = $hit->next_hsp) { 
    push(@list, $hsp); 
} 

Ora sto pensando che ci potrebbero essere modi migliori per fare questo in meno codice. Cosa dici, impilatori?

+0

Mostraci programmi di dimostrazione completi, in modo che possiamo vedere cose come come hai ottenuto $ hit. –

risposta

3

Dipende interamente dall'implementazione dell'iteratore. Se next_hsp è l'unico metodo disponibile, lo stai facendo correttamente.

5

Tutti gli iteratori che abbia mai visto restituiscono undef per indicare che sono esauriti. Pertanto dovresti scrivere while (defined(my $hsp = $hit->next_hsp)). L'esempio seguente dimostra l'errore nella domanda che verifica la verità (abortisce a 1) anziché la definizione (passa 'liftoff').

use 5.010; 
my $hit = __PACKAGE__; 

sub next_hsp { 
    state $i; 
    $i++; 
    return ['mumble', 4, 3, 2, 1, 0, 'liftoff']->[$i]; 
} 

# insert snippet from question here 
+0

Questo è un buon punto. Rende l'intera cosa ancora più ingombrante, ma hai ragione. – Mithaldu

+2

Un pattern comune è per un iteratore semplicemente "return" senza argomenti alla fine. In un contesto scalare che si trasforma in 'undef', ma se dici' my ($ hsp) = $ hit-> next_hsp', allora l'iteratore può tranquillamente restituire un valore di undef (o qualsiasi altra cosa che possa essere interpretata come falsa) nei casi dove ha senso farlo. Questo funziona perché un elenco contenente 1 valore sarà booleano true indipendentemente dal fatto che il valore sia falso o addirittura undef. –

+2

Tutti gli iteratori? Ho visto un numero abbastanza infinito. :) –

3

Non preoccuparti per giocare a golf, il codice che avete sembra proprio bene (a parte le altre risposte sull'utilizzo defined). Tuttavia, se ti ritrovi a ripetere questo schema, mi vengono in mente due cose.

Il primo è ovvio, il refactoring in una funzione di utilità, in modo da avere my @list = expand($hit).

La seconda domanda è un po 'più profondo - ma per me gli odori più di giocare a golf. L'intero punto degli iteratori è consumare quando ne hai bisogno, quindi se ti ritrovi a farlo spesso, sei sicuro che sia davvero la cosa giusta da fare? Forse stai spostando questi dati fuori dalla tua API, quindi sei vincolato alle scelte degli altri, ma se hai la possibilità di consumare un iteratore piuttosto che un elenco, forse questa sarà una soluzione più pulita.

Problemi correlati