write seqio read descargar bio python perl iterator

seqio - ¿Cuál es la versión de Perl de un iterador de Python?



read fasta python (8)

Aquí hay un buen ejemplo práctico y un artículo PDF ... pero estoy demasiado oxidado en Perl para intentar implementar su desafío directamente (como verá, tanto el ejemplo como el enfoque en el PDF usan un enfoque menos directo). )

Estoy aprendiendo Perl en mi trabajo y disfrutándolo. Normalmente hago mi trabajo en Python, pero el jefe quiere Perl.

La mayoría de los conceptos en Python y Perl combinan muy bien: diccionario Python = hash Perl; Tupla de Python = lista de Perl; Lista de Python = matriz de Perl; etc.

Pregunta: ¿Existe una versión de Perl de la forma Python de un Iterator / Generador?

Un ejemplo: una forma clásica de Python para generar los números de Fibonacci es:

#!/usr/bin/python def fibonacci(mag): a, b = 0, 1 while a<=10**mag: yield a a, b = b, a+b for number in fibonacci(15): print "%17d" % number

Los iteradores también son útiles si desea generar una subsección de una lista mucho más grande según sea necesario. Las ''listas'' de Perl parecen más estáticas, más como una tupla de Python. En Perl, ¿puede foreach ser dinámico o solo se basa en una lista estática?

La forma Python de Iterator es una forma a la que me he acostumbrado, y no la encuentro documentada en Perl ... Además de escribir esto en bucles o recursivamente o generar una gran lista estática, ¿cómo puedo (por ejemplo) escribir la subrutina de Fibonacci en Perl? ¿Hay algún yield Perl que me falta?

Específicamente, cómo escribo esto:

#!/usr/bin/perl use warnings; use strict; # yes -- i use those! sub fibonacci { # What goes here other than returning an array or list? } foreach my $number (fibonacci(15)) { print $number . "/n"; }

Gracias de antemano por ser amable con el novato ...


Aquí hay una respuesta adaptada para ajustarse a la pregunta planteada originalmente.

Cualquier módulo perl que implemente listas perezosas (por ejemplo, List :: Gen, Memoize, etc.) y también le permita suministrar su propia subrutina de generador (no me refiero a ''generador'' como en Python) le permitirá hacer lo que se muestra en este ejemplo. Aquí el módulo que produce la lista de forma perezosa se llama Alef.

#!/usr/bin/perl -w use strict; use warnings; use Alef; my $fibo; BEGIN { my ($a, $b) = (0, 1); $fibo = sub { ($a, $b) = ($b, $a+$b); $a; } } my $fibonacci = new Alef($fibo); foreach my $number ($fibonacci->take(15)){ print $number . "/n"; }

Aquí está el resultado:

[spl @ briareus ~] $ ./fibo.pl 0 1 1 2 3 5 8 13 21 34 55 89 144 233 377

No hay nada mágico sucediendo detrás de escena con el módulo de lista perezosa que se usa aquí. Así es como se ve la subrutina de toma de Alef.

sub take { my ($self,$n) = (@_); my @these = (); my $generator = $self->{''generator''}; for (1..$n){ push(@these,$self->{''this''}); $self->{''this''} = &$generator($self->{''this''}); } @these; }


El concepto de iterador es un poco diferente en Perl. Básicamente, desea devolver una subrutina de un solo uso "cerrada" sobre las variables persistentes.

use bigint; use strict; use warnings; sub fibonacci { my $limit = 10**( shift || 0 ); my ( $a, $b ) = ( 0, 1 ); return sub { return if $a > $limit; ( my $r, $a, $b ) = ( $a, $b, $a + $b ); return $r; }; } my $fit = fibonacci( 15 ); my $n = 0; while ( defined( my $f = $fit->())) { print "F($n): $f/n"; $n++; }

Y si no te gusta el bucle while, entonces aquí hay dos disparos de azúcar sintáctico, que básicamente logran un ciclo de cada elemento .:

sub iterate ($$) { my $iter = shift; my $action = shift; while ( defined( my $nextval = $iter->())) { local *_ = /$nextval; $action->( $_ ); } return; } iterate fibonacci( 15 ) => sub { print "$_/n"; }; sub iter (&$) { my $action = shift; my $iter = shift; while ( defined( my $nextval = $iter->())) { local *_ = /$nextval; $action->( $_ ); } return; } iter { print "$_/n" } fibonacci( 15 );


El excelente libro Perl de orden superior (disponible de forma gratuita en el enlace especificado) contiene mucha información sobre temas relacionados, y en particular tiene un capítulo completo sobre iteradores. Por "orden superior" el autor implica usar las habilidades de Perl como un lenguaje funcional con funciones de primera clase para implementar todo tipo de cosas interesantes. Realmente es un libro muy bueno, leo la mayor parte y los capítulos sobre iteradores y transmisiones son geniales. Recomiendo por lo menos hojearlo si planeas escribir el código de Perl.


En este caso, se puede usar la memorización.

use strict; use warnings; use Memoize; memoize(''fib''); foreach my $i (1..15) { print "$i -> ",fib($i),"/n"; } sub fib { my $n = shift; return $n if $n < 2; fib($n-1) + fib($n-2); }


Existe un método similar para producir un iterador / generador, pero no es un "ciudadano de primera clase" como lo es en Python.

En Perl, si no ve lo que quiere (¡después de un viaje OBLIGATORIO a CPAN PRIMERO !), Puede lanzar el suyo propio que sea similar a un iterador de Python basado en cierres de Perl y una subrutina anónima.

Considerar:

use strict; use warnings; sub fibo { my ($an, $bn)=(1,0); my $mag=(shift || 1); my $limit=10**$mag; my $i=0; return sub { ($an, $bn)=($bn, $an+$bn); return undef if ($an >=$limit || wantarray ); return $an; } } my $num; my $iter=fibo(15); while (defined($num=$iter->()) ) { printf "%17d/n", $num; }

El sub fibo mantiene un closure Perl que permite mantener las variables persistentes. Puede hacer lo mismo teniendo un módulo, similar a C / C ++. Dentro de fibo una subrutina anónima hace el trabajo de devolver el siguiente elemento de datos.

Para citar de la Biblia de Perl "Serás miserable hasta que aprendas la diferencia entre el contexto escalar y de la lista" - p 69 (Un libro altamente recomendado por cierto ...)

En este caso, el sub annon solo devuelve un solo valor. El único mecanismo de bucle que conozco en Perl que puede funcionar en contexto escalar es while ; Los otros intentan llenar la lista antes de proceder, creo. Por lo tanto, si llama al sub anon en el contexto de la lista, devolverá diligentemente el siguiente número de Fibonacci, a diferencia de los iteradores de Python, y el bucle terminará. Es por eso que pongo el return undef if .... wantarray porque no funciona en el contexto de la lista como está escrito.

Hay formas de arreglar eso. De hecho, puede escribir subrutinas que actúen como map etc. pero no es tan sencillo como el rendimiento de Python. Necesitará una función adicional para usar dentro de un bucle foreach. La compensación es el enfoque de Perl tiene un tremendo poder y flexibilidad.

Puede leer más sobre los iteradores de Perl en el excelente libro de Mark Jason Dominus "Higher Order Perl" El Capítulo 4 trata sobre Interators brian d foy también tiene un excelente article sobre Interators en Perl Review.


Hay algunos módulos de iterador / generador en CPAN que podrían ayudar aquí. Aquí está su ejemplo directamente traducido al módulo Coro::Generator :

use 5.016; use warnings; use Coro::Generator; sub gen_fibonacci { my $mag = shift; generator { my ($a, $b) = (0, 1); while ($a <= 10 ** $mag) { yield $a; ($a, $b) = ($b, $a + $b); } yield undef; # stop it! }; } my $fibonacci = gen_fibonacci(15); while (defined (my $number = $fibonacci->())) { printf "%17d/n", $number; }


Para una solución aún más flexible que los generadores de Python, he escrito el módulo List::Gen en CPAN que proporciona matrices de generador perezoso de acceso aleatorio:

use List::Gen; my $fib; $fib = cache gen {$_ < 2 ? $_ : $$fib[$_ - 1] + $$fib[$_ - 2]}; say "@$fib[0 .. 15]"; # 0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610

Dado que los generadores pretenden ser matrices, pueden mezclarse perfectamente con el código perl normal. También hay un enfoque orientado a objetos:

my $fib; $fib = cache gen {$_ < 2 ? $_ : $fib->get($_ - 1) + $fib->get($_ - 2)}; say join '' '' => $fib->slice(0 .. 15);

En cada caso, el generador es flojo, no calcula nada en la creación, y luego calcula solo los valores necesarios para satisfacer los cortes. La definición recursiva de la secuencia de Fibonacci se llama a sí misma muchas veces, por lo que la función de cache se utiliza para asegurarse de que cada valor se calcule una sola vez.

También puede usar generadores como iteradores:

while (my $num = $fib->next) { last if $num > 10**15; print "$_/n"; }

$fib->next también se puede escribir $fib->() . Como el generador todavía tiene acceso aleatorio, puede $fib->reset() o $fib->index = 10;

Hazme saber si tienes alguna pregunta.

Actualizar:

He lanzado una nueva versión del módulo (0.80) que facilita el uso de algoritmos iterativos en generadores. Aquí hay un ejemplo que refleja fielmente el ejemplo del OP:

use List::Gen ''*''; sub fibonacci { my $limit = 10**shift; my ($x, $y) = (0, 1); While {$_ < $limit} gather { ($x, $y) = ($y, take($x) + $y) } } say for @{fibonacci 15};

si usas use bigint; antes o en la parte superior del submarino, puedes, por supuesto:

say for @{fibonacci 400}; # or more