Python 迭代器的 Perl 版本是什么?
问题描述
我在工作中学习 Perl,并乐在其中.我通常用 Python 做我的工作,但老板想要 Perl.
I am learning Perl at my work and enjoying it. I usually do my work in Python but boss wants Perl.
Python 和 Perl 中的大多数概念都非常匹配:Python dictionary=Perl hash;Python 元组=Perl 列表;Python 列表=Perl 数组;等等.
Most of the concepts in Python and Perl match nicely: Python dictionary=Perl hash; Python tuple=Perl list; Python list=Perl array; etc.
问题:有没有 Perl 版本的 Python 形式的 Iterator/生成器?
Question: Is there a Perl version of the Python form of an Iterator / Generator?
一个例子:生成斐波那契数的经典 Python 方法是:
An example: A Classic Python way to generate the Fibonacci numbers is:
#!/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
如果您想根据需要生成更大列表的子部分,迭代器也很有用.Perl 的列表"看起来更静态——更像是一个 Python 元组.在 Perl 中,foreach
可以是动态的还是仅基于静态列表?
Iterators are also useful if you want to generate a subsection of a much larger list as needed. Perl 'lists' seem more static - more like a Python tuple. In Perl, can foreach
be dynamic or is only based on a static list?
Iterator 的 Python 形式是我已经习惯的一种形式,但我没有发现它在 Perl 中记录...ex) 在 Perl 中编写斐波那契子程序?是否有我缺少的 Perl yield
?
The Python form of Iterator is a form that I have gotten used to, and I do not find it documented in Perl... Other than writing this in loops or recursively or generating a huge static list, how do I (for ex) write the Fibonacci subroutine it in Perl? Is there a Perl yield
that I am missing?
具体来说——我该怎么写:
Specifically -- how do I write this:
#!/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 . "
"; }
在此先感谢您对新手的善意...
Thanks in advance to being kind to the newbie...
解决方案
为了比 Python 的生成器更灵活的解决方案,我编写了模块 List::Gen 在 CPAN 上提供随机访问惰性生成器数组:
For an even more flexible solution than Python's generators, I have written the module List::Gen on CPAN which provides random access lazy generator arrays:
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
由于生成器伪装成数组,它们可以与普通的 perl 代码无缝混合.还有一种面向对象的方法:
Since generators pretend to be arrays, they can mix seamlessly with normal perl code. There is also an object oriented approach:
my $fib; $fib = cache gen {$_ < 2 ? $_ : $fib->get($_ - 1) + $fib->get($_ - 2)};
say join ' ' => $fib->slice(0 .. 15);
在每种情况下,生成器都是惰性的,在创建时不计算任何内容,然后只计算满足切片所需的值.斐波那契数列的递归定义多次调用自身,所以使用 cache
函数来确保每个值只计算一次.
In each case, the generator is lazy, calculating nothing upon creation, and then calculating only those values required to satisfy the slices. The recursive definition of the Fibonacci sequence calls itself many times, so the cache
function is used to make sure each value is only calculated once.
您也可以将生成器用作迭代器:
You can also use generators as iterators:
while (my $num = $fib->next) {
last if $num > 10**15;
print "$_
";
}
$fib->next
也可以写成$fib->()
.由于生成器还是随机访问的,所以可以$fib->reset()
或者$fib->index = 10;
$fib->next
can also be written $fib->()
. Since the generator is still random access, you can $fib->reset()
or $fib->index = 10;
如果您有任何问题,请告诉我.
Let me know if you have any questions.
更新:
我发布了该模块的新版本 (0.80),它可以更轻松地在生成器中使用迭代算法.这是一个与 OP 的示例非常相似的示例:
I have released a new version of the module (0.80) that makes it easier to use iterative algorithms in generators. Here is an example that closely mirrors the OP's example:
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};
如果你在 sub 之前或顶部 使用 bigint;
,当然可以:
if you use bigint;
before or at the top of the sub, you can of course:
say for @{fibonacci 400}; # or more
相关文章