下面的Perl片段应该打印由哈希值引用的数组的前5项,如果数组更短则打印更少。
while ( my ($key,$value) = each %groups ) {
print "$key: \n";
my @list = grep defined, @{$value};
my @slice = grep defined, @list[0..4];
foreach my $item ( @slice ) {
print " $item \n";
}
print " (", scalar @slice, " of ", scalar @list, ")\n";
}
我不认为第一个grep defined
是必要的,但它不会造成任何伤害,它应该保证切片之前没有未定义的数组成员。第二个grep defined
是在slice
小于5时在@list
的结果中移除未定义的数组成员。
%groups
已经被重复调用填充:
$groups{$key} = () unless defined $groups{$key};
push @{$groups{$key}}, $value;
大部分时间它都可以正常工作:
key1:
value1
value2
value3
value4
value5
(5 of 100)
但有时 - 我在什么情况下没有解决 - 我明白了:
key2:
value1
(1 of 5)
key3:
value1
value2
(2 of 5)
我希望打印列表的长度为x
(x of y)
为min(5,y)
什么可能导致这种行为?
答案 0 :(得分:8)
将grep
与@list
的数组切片一起使用可自动生成元素并扩展数组。
@foo = (1,2,3);
@bar = @foo[0..9999];
print scalar @foo; # => 3
@foo = (1,2,3);
@bar = grep 1, @foo[0..9999];
print scalar @foo; # => 10000
在Perl想要遍历数组切片的其他上下文中也会发生这种情况。
@foo = (1,2,3);
foreach (@foo[0..9999]) { }
print scalar @foo; # => 10000
@foo = (1,2,3);
@bar = map { } @foo[0..9999];
print scalar @foo; # => 10000
那么解决方法是什么?
对范围或grep
操作数
@bar = grep 1, @foo[0..(@foo>=9999?9999:$#foo)];
@bar = grep 1, @foo>=9999 ? @foo[0..9999] : @foo;
使用临时数组变量
@bar = grep 1, @tmp=@foo[0..9999]
(@FMc建议)使用map
设置中间数组
@bar = grep 1, map { $list[$_] } 0..9999;
使用数组索引而不是直接使用数组
@bar_indices = grep defined($foo[$_]), 0..9999;
@bar = @foo[@bar_indices];
@bar = @foo[ grep defined($foo[$_]), 0..9999 ];