什么是最令人愉快的惯用写作方式
for (take(100,@array)) {...}
假设没有take
(它接受列表的第一个 n 元素,但是如果没有 n 元素则更少)?
我考虑的事情:
for (@array[0..99]) {...}
但如果@array
少于100个元素
for (@array[0..min(99,$#array)]) {...}
但min
不是Perl中的标准函数
for (splice @array,0,100) {...}
更改数组。
答案 0 :(得分:7)
for (@array[0..min(99,$#array)]) {...}
但是min不是Perl中的标准函数
min
是模块List::Util中的标准函数,它是5.7.3中核心的一部分。
use List::Util qw(min);
for (@array[0..min(99,$#array)]) { # generator in 5.8.8+
...
}
请注意,perl 5.8.8以及之前的版本可能足够聪明,可以将表达式理解为生成器而不是切片。也就是说,从@array一次一个地获取元素0到$ terminus,而不是取出和复制一个匿名片。
答案 1 :(得分:6)
您想要CPAN模块List::Slice
use List::Slice 'head';
foreach my $elem ( head 100, @things ) { ... }
答案 2 :(得分:2)
您已经表明您发现以下内容最干净:
take(100, @array)
所以回答你的问题是什么是最干净的,那就是!我不明白为什么你要找一个替代品。
答案 3 :(得分:2)
如何使用map
:
my @array = qw ( 1 2 3 4 );
print join "\n", map { $_ // () } @array[0..10];
这会从列表中获取10个元素,但会对其应用“已定义”测试 - 如果未定义,则返回空列表。
所以你可以:
for ( map { $_ // () } @array[0..100] ) {
#do something
}
注意 - //
是一个已定义的或运算符,仅可从perl 5.10+获得。您可以使用defined
三元组:
print join "\n", map { defined ? $_ : () } @array[0..10];
答案 4 :(得分:1)
您可以在循环中添加额外的检查,以便在到达结束时中断。
my @arr = (1 .. 90);
for ( @arr[0..99]) {
last unless defined $_;
say;
}
但这对于中间有undef
值的数组不起作用,例如:
my @foo = (1, 2, undef, 4);
my @bar;
$bar[2] = 'foo'; # (undef, undef, 'foo')
答案 5 :(得分:1)
其他回复已涵盖这一点,但为了彻底, 在CPAN上实施了几个“南瓜perl”gather/take
:-)
还有Damian Conway的Perl6::Gather
几乎相同但需要Perl6::Export
。
他们让您以您想要的方式处理列表。 例如到“take
”字母表的一半:
perl -E 'use List::Gather; @lpha = ("a" .. "z");
@half = gather { for (@lpha){ take $_ if gathered < 13 } } ; say @half'
abcdefghijklm
如果我们还没到中途,那么或更少:
perl -E 'use List::Gather; @lpha = ("a" .. "c");
@half = gather { for (@lpha) { take $_ if gathered < 13 } } ; say @half'
abc
使用List::Gather
gather
块可以循环(因为gather{}
内部的词法作用域??)并且块内需要主题$_
:
perl -E 'use List::Gather; @lpha = ("a" .. "g");
@half = gather for (@lpha) { take $_ if gathered < 13 }; say @half'
使用Syntax::Keyword::Gather
,您可以在gather{}
块中执行此操作(List::Gather
也可以这样做):
perl -E 'use Syntax::Keyword::Gather; @lpha = ("a".."g");
@half = gather { for (@lpha){ take if gathered < 13 } }; say @half'
我发现gather/take
是使用列表的一种不错的替代方法。是否足够好,有一天可以发送perl - 比如在List::Util
中 - 是你问题的一个有趣的隐含部分;-)但它们是CPAN上的。
<强>后记强>
为了解决@simbabque,@ azid和@Joachim Breitner提出的关于defined
的一些问题,可以在take()
例程中添加更多检查。
我在这里使用Ingy的boolean
:
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"
]
答案 6 :(得分:0)
我认为你应该使用迭代器模式,即
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);
}
}
PS。有一个限制,undef
不能成为@data