2010-10-10 13 views
6

que tienen un iterador con esta interfaz: $ éxito-> next_hsp¿Cuál es la forma más elegante en Perl para expandir un iterador en una lista?

La implementación actual de listify es:

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

Ahora estoy pensando que podría haber mejores maneras de hacer esto en menos código. ¿Qué dices, apiladores?

+0

Muéstranos programas de demostración completos, para que podamos ver cosas como cómo obtuviste '$ hit'. –

Respuesta

3

Todo depende de la implementación del iterador. Si next_hsp es el único método disponible, entonces lo está haciendo bien.

5

Todos los iteradores que he visto devuelven undef para indicar que están agotados. Por lo tanto, debe escribir while (defined(my $hsp = $hit->next_hsp)). El siguiente ejemplo demuestra la falla en la pregunta que prueba la verdad (aborta en 1) en lugar de la definición (pasa el 'despegue').

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

Ese es un buen punto. Hace que todo sea aún más difícil de manejar, pero tienes razón. – Mithaldu

+2

Un patrón común es para un iterador simplemente 'return' sin args al final. En un contexto escalar que se convierte en 'undef' pero si dices' my ($ hsp) = $ hit-> next_hsp', el iterador puede devolver de forma segura un valor de undef (o cualquier otra cosa que pueda interpretarse como falsa) en los casos donde tiene sentido hacerlo Esto funciona porque una lista que contiene 1 valor será booleana verdadera independientemente de si el valor es falso o incluso undef. –

+2

¿Todos los iteradores? He visto un número bastante infinito. :) –

3

No se preocupe por la práctica del golf, el código que tiene se ve muy bien (aparte de las otras respuestas acerca del uso de defined). Sin embargo, si te encuentras repitiendo este patrón, me vienen a la mente dos cosas.

La primera es obvia, refactorearlo en una función de utilidad, para que tenga my @list = expand($hit).

La segunda pregunta es un poco más profundo - pero me huele más que jugar al golf. El objetivo de los iteradores es consumir a medida que los necesita, de modo que si te encuentras haciendo esto a menudo, ¿estás seguro de que es realmente lo correcto? Tal vez estés moviendo estos datos fuera de tu propia API, por lo que estás obligado a elegir otros, pero si tienes la opción de consumir un iterador en lugar de una lista, quizás esta sea una solución más limpia.

Cuestiones relacionadas