我该如何在Perl 6中缩短一个数组?

8

如何在Perl 6中切断数组或数组引用?

在Perl 5中,我可以这样做:

my $d = [0 .. 9];
$#$d = 4;

在Perl 6中,如果我尝试这样做,就会出现错误:

my $d = [0 .. 9];
$d.end = 4; # Cannot modify an immutable Int

这样做是可行的,但看起来不如 Perl 5 的方式美观,并且可能比较昂贵:

 $d.=splice(0, 5);

5
在Perl5中,如果数组@a中的元素少于5个时,我会使用splice(@a, 5);命令,因为这样不会拉伸数组。(这还可以让你使用期望的元素数量,而不是比期望少一个。同时避免了构建和设置魔法标量的过程。) - ikegami
3个回答

13

有一种简单的方法:

my $d = [0..9];

$d[5..*] :delete;

如果数组是无限的,那么这可能会产生问题。

$d.splice(5)也有同样的问题。

在平均情况下,您最好的选择可能是$d = [ $d[^5] ],特别是当您对数组一无所知,需要一个可变数组时。

如果您不需要它是可变的,$d = $d[^5]返回一个列表可能更好。


1
你能描述一下 ^5 是干什么的吗?(尤其是当初始元素少于 4 个时) - ysth
1
@ysth "插入符号是一个前缀运算符,用于从零开始构建数字范围。" 我在我的答案中包含了这个,但我无法进一步扩展它。如果范围超出现有列表/数组的末尾,它将返回额外的元素作为 (Any) 类型的 Array(Nil) 类型的 List。然后你可以对该元素进行赋值。正如 @ikegami 所称,数组将会“拉伸”。(Array)(List)(Nil)(Any) 不等同,并且行为不同。 - G. Cito

6

splice 可能是最好的选择,但您也可以使用^N范围构造器快捷方式将其缩短为五个元素(我称之为“直到”“运算符”,但我确定有一个更正确的名称,因为它是Range的构造器):

> my $d = [ 0 .. 9 ];
> $d.elems
> 10
> $d = [ $d[^5] ]
[0 1 2 3 4]
> $d.elems
5
> $d
[0 1 2 3 4]

“caret”是构建从零开始的数字范围的前缀运算符。
                                                                                    (来自Range文档

可以说perl6在某种意义上是“perl风格”的,因为它通常具有某些操作的显式版本(使用一种“可预测”的语法 - 方法、例程和:adverb等),如果你不熟悉该语言,这些版本是可以理解的,然后是类似于快捷方式的变体。

我不确定哪种方法(splice与快捷方式相比或像Brad Gilbert提到的使用:delete)在速度或内存使用方面有优势。如果你运行:

perl6 --profile -e 'my $d = [ 0 .. 9 ]; $d=[ $d[^5] ]'
perl6 --profile -e 'my $d = [ 0 .. 9 ]; $d.=splice(0, 5);'

您可以看到微小的差异,如果与真实的程序和工作负载进行比较,则差异可能更显著。


1
perl -E 'my $d = [ 0 .. 9 ];$#$d = 4;say @$d' 打印出 01234,因此在 $d = [ $d[^4] ] 中存在一个偏移错误。 - Brad Gilbert

2
另一种选择是使用xx运算符:
my $d = [0..9];

$d.pop xx 4;  #-> (9 8 7 6)
say $d;       #-> [0 1 2 3 4 5]

$d = [0..9];

$d.shift xx 5 #-> (0 1 2 3 4)
say $d;       #-> [5 6 7 8 9)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接