【发布时间】:2012-02-01 13:51:28
【问题描述】:
我有一个类似 ("valueA", "valueB", "valueC", "valueD") 等的数组。我想从(例如)“valueC”的第一个实例开始循环遍历数组的值.值“valueC”的第一个实例之前的数组中的所有内容都应被忽略;所以在这种情况下,只有“valueC”和“valueD”会被循环处理。
我可以在循环中放置一个条件,但是有没有更简洁的方式来使用 perl 来表达这个想法?
【问题讨论】:
我有一个类似 ("valueA", "valueB", "valueC", "valueD") 等的数组。我想从(例如)“valueC”的第一个实例开始循环遍历数组的值.值“valueC”的第一个实例之前的数组中的所有内容都应被忽略;所以在这种情况下,只有“valueC”和“valueD”会被循环处理。
我可以在循环中放置一个条件,但是有没有更简洁的方式来使用 perl 来表达这个想法?
【问题讨论】:
my $seen;
for ( grep $seen ||= ($_ eq "valueC"), @array ) {
...
}
【讨论】:
$seen 变量用作标志:我已经看到起始值了吗? grep 遍历数组,如果还没有看到,它将比较的结果分配给看到。这样,在第一次出现 valueC 时, seen 将设置为 1,以后不会更改。 Grep 将仅返回来自 @array 且 $seen 为真的值,即 1。
grep { $seen = $seen || $_ eq 'valueC' } @array。一旦 $seen 设置为 true,它就保持为 true。
我认为您还需要检查数组中是否存在“valueC”。
希望这会有所帮助。
use strict;
use warnings;
use List::Util qw(first);
my @array = qw(valueA valueB valueC valueD);
my $starting_element = 'valueC';
# make sure that the starting element exist inside the array
# first search for the first occurrence of the $stating_element
# dies if not found
my $starting_index = first { $array[$_] eq $starting_element } 0 .. $#array
or die "element \"$starting_element\" does not exist inside the array";
# your loop
for my $index ($starting_index .. $#array) {
print $array[$index]."\n";
}
【讨论】:
my $seen;
for ( @array ) {
$seen++ if /valueC/;
next unless $seen;
...
}
但是$seen 有点笨拙。 flip-flop operator 看起来更整洁 IMO:
for ( @array ) {
next unless /^valueC$/ .. /\0/;
# or /^valueC$/ .. '' !~ /^$;
# or $_ eq 'valueC' .. /\0/;
...
}
或者简单地说(基于 ikegami 的建议):
for ( grep { /^valueC$/ .. /(*FAIL)/ } @array ) { ... }
【讨论】:
/(?!)/ 和 /(*FAIL)/ 是理想的,但你实际上想要一些不是数字常量的 false,所以 do{0} 可以。
sub{ 0 } 和 !! 0 不起作用。
sub { 0 } 返回一个正确的代码引用——sub { 0 }->() 可以工作——而!!0 是一个常量。
use List::MoreUtils qw( first_index );
foreach my $item ( @array[ ( first_index { $_ eq 'ValueC' } @array ) .. $#array ] ){
# process $item
}
【讨论】:
my $start = 0;
++$start while $start < @array && $array[$start] ne 'valueC';
后跟
for (@array[$start..$#array]) {
say;
}
或
for my $i ($start..$#array) {
say $array[$i];
}
【讨论】:
TIMTOWTDI,但我认为:
foreach my $item (@list) {
next if !$seen && ($item ne 'valueC');
$seen++;
...
}
既可读、正确又简洁。所有 /valueC/ 解决方案都将处理“DooDadvalueCFuBAr”之后的任何内容,而不是 OP 要求的内容。而且,不,您不需要触发器/范围运算符,并且事先检查是否存在真的很奇怪,除了需要一个可能的非核心包来执行一项相当微不足道的任务。 grep 解决方案真的让我头晕目眩,除了创建和折腾一个临时数组作为副作用。
如果你想花哨并避免''ifs':
foreach my $item (@list) {
$seen || ($item eq 'valueC') || next;
$seen++;
...
}
只是不要写回家。 :-)
【讨论】:
/valueC/,触发器仍然可以工作:next unless $_ eq 'valueC' .. '' !~ /^$/; 这个想法是引入触发器结构作为 TIMTOWDI 替代方案,仅此而已。
my $seen=0;,因为my $seen; 也可以。
next if !$seen || ($item ne 'valueC') 有效吗?我认为这总是会给你一个真正的价值。