Arrays 首先迭代perl数组中最多n个元素
最令人愉快的惯用写作方式是什么Arrays 首先迭代perl数组中最多n个元素,arrays,perl,loops,Arrays,Perl,Loops,最令人愉快的惯用写作方式是什么 for (take(100,@array)) {...} 假设没有take(它获取列表的前n个元素,但如果没有n个元素则更少) 我考虑的事情: for(@array[0..99]){…} 但如果@array的元素少于100个,则该操作将失败 for(@array[0..min(99,$#array)]{…} 但是min不是Perl中的标准函数 for(splice@array,0100){…} 这会改变数组 您可以在循环内部添加额外的检查,以在到达终点后中断
for (take(100,@array)) {...}
假设没有take
(它获取列表的前n个元素,但如果没有n个元素则更少)
我考虑的事情:
但如果for(@array[0..99]){…}
的元素少于100个,则该操作将失败@array
但是for(@array[0..min(99,$#array)]{…}
不是Perl中的标准函数min
这会改变数组for(splice@array,0100){…}
my @arr = (1 .. 90);
for ( @arr[0..99]) {
last unless defined $_;
say;
}
但对于介于unde
值之间的数组,这不起作用,例如:
my @foo = (1, 2, undef, 4);
my @bar;
$bar[2] = 'foo'; # (undef, undef, 'foo')
for(@array[0..min(99,$#array)]{…}
但是min不是Perl中的标准函数 是模块中的标准功能,从5.7.3开始,它是核心的一部分
use List::Util qw(min);
for (@array[0..min(99,$#array)]) { # generator in 5.8.8+
...
}
请注意,Perl5.8.8以后的版本,或者更早的版本,足够聪明,可以将该表达式理解为生成器而不是切片。也就是说,从@array一次提取一个元素0到$terminus,而不是提取和复制一个匿名切片。您已经指出,您发现以下内容最干净:
take(100, @array)
所以要回答你的问题,什么是最干净的,那就是!我不明白你为什么要寻找替代方案。使用
map
怎么样:
my @array = qw ( 1 2 3 4 );
print join "\n", map { $_ // () } @array[0..10];
这将从列表中获取10个元素,但对其应用“已定义”测试-如果未定义,则返回空列表
所以你可以:
for ( map { $_ // () } @array[0..100] ) {
#do something
}
注意-/
是一个定义的or运算符,仅在perl 5.10+中可用。您可以使用定义的三元:
print join "\n", map { defined ? $_ : () } @array[0..10];
你想要CPAN模块吗
其他的回答已经涵盖了这一点,但是,为了彻底起见,有几个“南瓜perl”
gather/take
在CPAN上的实现:-)
Perl6::Export
它们让你以你想要的方式处理列表。e、 g.要“取
”字母表的一半:
perl -E 'use List::Gather; @lpha = ("a" .. "z");
@half = gather { for (@lpha){ take $_ if gathered < 13 } } ; say @half'
abcdefghijklm
在gather{}
块中执行此操作(也可以使用List::gather
):
输出:
[
[0] "a",
[1] "b",
[2] "c",
[3] "d",
[4] "e",
[5] "f",
[6] "g",
[7] "x",
[8] "z"
]
我认为应该使用迭代器模式,即
my $iterator = create_iterator(100);
while (my $element = $iterator->()) {
...;
}
有limit
可能嵌入到迭代器创建中,即
sub create_iterator {
my $limit = shift;
my @data = (0 x 1000);
my $i = 0;
return sub {
return $data[$i++] if ($i < @data);
}
}
sub-create\u迭代器{
我的$limit=shift;
my@data=(0 x 1000);
我的$i=0;
返回接头{
如果($i<@data),则返回$data[$i++]if;
}
}
PS.有一个限制,
unde
不能成为@data
的一部分take
做什么?会做你想做的吗?不是真的;我正在寻找获取元素的方法。不仅仅是undef
。。。任何计算结果为false(0
,“
”)的内容,等等@zaid当然是。请随意编辑,我在打电话。“但这对介于未定义值之间的数组不起作用,比如这些”–这对我来说是一个阻碍,因为它看起来非常不可靠。@JoachimBreitner如果你不想在子例程中添加大量检查,你可以使用CPAN模块来完成该部分。是否合适?请参阅我的gather/take
响应的结尾,以获取一个示例。换句话说,编写一个子例程。问题与@simbabque的解决方案相同:如果没有定义所有元素,则会中断。可能是一种极端情况,但我不认为代码不可靠的原因。我认为在这里也会起作用:-Dperl-Mboolean-E'@array=(“a”。.g',”,unde,unde,“x”,“0”,“z”);打印联接“\n”,映射{boolean($\u)?$\u:()}@array[0..100];'代码>授权-它会根据其所做的操作过滤undef
。我不认为这是一个很大的问题,因为我很少有在循环上下文中操作的present-but-undf
;我希望有更优雅的东西,但我想这是最好的解决方案。你知道哪里有文件证明这不会生成临时列表吗?我知道,尽管这方面的文档也很简洁。@ThisSuitesBlack不,不,我不知道。我使用了一个tie()
d数组,该数组在每次抓取时都会发出吠声,以说服自己该优化已经到位。(每个循环一次连续抓取,而不是一次全部抓取。)方法不错!没想到。head
听起来像是一个基本的“实用程序”。。。对于列表;-)嗯,比起像gather/take
@G.Cito-yup这样的时髦东西,更“基本的实用程序”。请看是的,我希望这样的东西在语言本身中很容易表达,或者至少在默认情况下可以提供。唯一的缺点是,在for
循环中,此函数将n个元素复制到一个匿名数组中,然后进行迭代。相比之下,for
循环中的显式常规切片在每次迭代中逐个获取元素。除非n变大,否则这无关紧要。如果unde
在列表中,这与另一个答案的缺点是相同的。
perl -E 'use Syntax::Keyword::Gather; @lpha = ("a".."g");
@half = gather { for (@lpha){ take if gathered < 13 } }; say @half'
perl -E 'use boolean; use List::Gather;
@lpha = ("a" .. "g", "", undef, undef, "x", "0", "z");
@half = gather { for (@lpha){ take $_ if boolean($_) && gathered < 13 }};
use DDP; p @half;'
[
[0] "a",
[1] "b",
[2] "c",
[3] "d",
[4] "e",
[5] "f",
[6] "g",
[7] "x",
[8] "z"
]
my $iterator = create_iterator(100);
while (my $element = $iterator->()) {
...;
}
sub create_iterator {
my $limit = shift;
my @data = (0 x 1000);
my $i = 0;
return sub {
return $data[$i++] if ($i < @data);
}
}