在Perl中,有没有办法获取匿名数组末尾的一个片段?
这让我在过去的半小时里疯了。我有没有办法在匿名数组的末尾获取一个数组切片?我试过:在Perl中,有没有办法获取匿名数组末尾的一个片段?,perl,Perl,这让我在过去的半小时里疯了。我有没有办法在匿名数组的末尾获取一个数组切片?我试过: (拆分(“”,$test_行))[1..$#!] 我试过: (拆分(“”,$test_行))[1..-1] 但更糟糕的是,这两种方法都不起作用。我真的不想在中间数组中实例化一个额外的temp变量(我不需要)。我真的不想用难看的、不可读的一行(在网上找到了一些)。真的没有直截了当的方法吗?在您的示例中,列表不能从末尾分割。这主要是因为列表在Perl中不是正确的数据结构,而是解释器用来移动数据的结构。因此,知道您只能
(拆分(“”,$test_行))[1..$#!]
我试过:
(拆分(“”,$test_行))[1..-1]
但更糟糕的是,这两种方法都不起作用。我真的不想在中间数组中实例化一个额外的temp变量(我不需要)。我真的不想用难看的、不可读的一行(在网上找到了一些)。真的没有直截了当的方法吗?在您的示例中,列表不能从末尾分割。这主要是因为列表在Perl中不是正确的数据结构,而是解释器用来移动数据的结构。因此,知道您只能从一开始就对列表进行切片,您可以选择将其放入数组变量中,然后切片,更改算法以返回所需内容,或者执行以下操作: 如果要将此值分配给某个对象,可以在不需要的每个插槽中使用
unde
:
my (undef, @list) = split ' ' => $test_line;
如果你发布更多的代码,我可以修改
或者,您可以使用函数式编程中的一些工具。这对函数drop
和take
可用于调整列表大小,而无需其他变量:
sub take {
my $n = shift;
@_[0..$n-1]
}
sub drop {
my $n = shift;
@_[$n..$#_]
}
然后你的例子就变成了
drop 1, split ' ' => $test_line;
drop 1
通常也称为tail
sub tail {drop 1, @_}
当然,由于所有这些都很短,如果您想将其内联:
sub {shift; @_}->(split ' ' => ...)
我不相信您可以为任意列表表达式的最后一个元素指定索引,但是:
split(' ', (split ' ', $test_line, 2)[1])
顺便说一句,这里没有匿名数组(或者在你最初的问题中),只有列表。当OP提到切片时,我想到:
如果您愿意拆分两次:
my @g = (split ' ', $test_str)[1..split(' ', $test_str)];
或更正确(因为split返回找到的字段数(比最后一个字段的索引多一个,因为它是基于0的):
不幸的是,它们在“warnings”pragma下抛出了一个不推荐使用的警告,并破坏了@uux的内容(除非您使用的是5.12,否则就很好,否则使用临时变量、内联子变量或循环)。您可以在数组下标中使用负范围来处理从末尾开始的任意数量的元素:
my $x = join ' ' => 'a' .. 'z';
my @x = (split ' ', $x)[-13 .. -1];
但是,这要求您知道split
结果中的元素总数,以便仅消除第一个元素
如果这只发生在一个地方,则使用do
块应该可以:
my $x = join ' ', 'a' .. 'z';
my @x = do { my @y = (split ' ', $x); @y[1 .. $#y] };
在您的情况下,如果假定子例程经常使用,我会将整个操作分解为子例程,将字符串而不是拆分的结果传递给子例程(也可以通过允许用户传递拆分模式进一步推广:
my $x = join ' ', 'a' .. 'g';
my @x = skip_first_n_from_split(3, $x);
print Dump \@x;
sub skip_first_n_from_split {
my ($n, $x) = @_;
my @y = split ' ', $x;
return @y[$n .. $#y];
}
玩得开心:
#!/usr/bin/perl
use strict; use warnings;
my $x = join ' ', 1 .. 8;
my @skippers = map make_skipper(' ', $_), 0 .. 7;
print "@$_\n" for map $_->($x), @skippers;
sub make_skipper {
my ($pattern, $n) = @_;
return sub {
my $string = shift;
my $i = 0;
return [ grep $i++ >= $n, split $pattern, $string ];
}
}
输出:
1 2 3 4 5 6 7 8
2 3 4 5 6 7 8
3 4 5 6 7 8
4 5 6 7 8
5 6 7 8
6 7 8
7 8
8
1 2 3 4 5 6 7 8
2 3 4 5 6 7 8
3 4 5 6 7 8
4 5 6 7 8
5 6 7 8
6 7 8
7 8
8BrowserUK刚刚在Perlmonks上“巧妙地”发表了这篇文章,这就是你要做的:
my @slice = sub{ @_[1..$#_] }->( split ' ', $test_line );
我想最好的答案是额外的temp变量。在第一行中,$#
不起作用的原因是@
不是表达式中的列表。我的想法是:我的%test\u hash=(拆分(''.$test\u line))[1..$#;在这种情况下,您的方法运行良好,但我希望有更通用的方法,这样当我不想要前10项时,我就不会被困在写10次undef…@Eli=>遗憾的是,这不是perl5中列表切片的功能。通用的解决方案类似于drop
或take
在您的内容中,您还可以使用grep删除不需要的项。回答很好。有一个线性解决方案,但它们确实不属于生产代码。好吧,这不是我想要的答案,但考虑到约束条件,这似乎是最好的答案。我想这只是我不喜欢Perl的另一个原因。@Eli=>Keep learning,我发现在Perl语法似乎不太适合这个问题的大多数地方,通常会有一种不同的方法来解决这个问题,结果会更干净。不是最漂亮的方法,调用split
两次。你也可以使用split”“=>($test\u line=~/\s+(.*)/s&&1)
,但我不主张这样做。也许这不是最漂亮的,但至少它简短且相对简单。
1 2 3 4 5 6 7 8
2 3 4 5 6 7 8
3 4 5 6 7 8
4 5 6 7 8
5 6 7 8
6 7 8
7 8
8
my @slice = sub{ @_[1..$#_] }->( split ' ', $test_line );