准系统解决方案
让我们从一个非常简单的打印序列要点的解决方案开始。它不会处理您添加到问题中的细节,但这是一个很好的起点:
sub seq-range-gist ( @seq ) {
my @pairs = @seq.pairs;
join "\n", @pairs.head(3)».gist, '...', @pairs.tail(2)».gist
}
.kv
与之不同的是,将其主语转换为形式key1, value1, key2, value2, key3, value3, ...
,即,如果其主语包含3个元素,.pairs
则将6个元素转换为形式key1 => value1, key2 => value2, key3 => value3, ...
。
我之所以使用它.pairs
不是.kv
部分原因是因为这意味着我可以».gist
稍后在代码中使用它来轻松地key1 => value1
为每个元素获得漂亮的显示。我们将在下面进行修改,但这是一个很好的习惯用法。
该.head
和.tail
电话是创建从调用者列表中的第一个和最后N个元素的小名单的惯用方式(只要不偷懒,更多的是在MO)。
给定此初始解决方案,将say seq-range-gist (0,1 ... Inf)[^10]
显示:
0 => 0
1 => 1
2 => 2
...
8 => 8
9 => 9
接下来,我们希望能够“仅从打印输出中删除第一个元素……”。不幸的是say seq-range-gist (0,1 ... Inf)[1..9]
显示:
0 => 1
1 => 2
2 => 3
...
7 => 8
8 => 9
我们希望左侧=>
的数字保留原始序列的编号。为了实现这一点,我们从想要提取的范围中拆分了基础序列。我们添加第二个参数/参数@range
,并追加[@range]
到子的第二行:
sub seq-range-gist ( @seq, @range ) {
my @pairs = @seq.pairs[@range];
现在我们可以编写say seq-range-gist (0,1 ... Inf), 1..9
显示:
1 => 1
2 => 2
3 => 3
...
8 => 8
9 => 9
在您的问题中,您使用格式aINDEX = VALUE
而不是INDEX => VALUE
。为了允许对要点进行自定义,我们添加了第三个&gist
例程参数/自变量,然后调用它而不是内置.gist
方法:
sub seq-range-gist ( @seq, @range, :&gist ) {
my @pairs = @seq.pairs[@range];
join "\n", @pairs.head(3)».&gist, '...', @pairs.tail(2)».&gist
}
请注意,seq-range-gist
sub 主体中的“方法”调用现在.&gist
不是.gist
。该语法会.&foo
调用一个子项 &foo
(通常通过编写来调用foo
),并将左侧的引发剂.
作为$_
该子项的参数传递。
还要注意,我在&gist
参数前面加上了,从而使参数成为了一个命名的参数:
。
现在say seq-range-gist (0,1 ... Inf), 1..9, gist => { "a{.key} = {.value}" }
显示:
a1 = 1
a2 = 2
a3 = 3
...
a8 = 8
a9 = 9
上光油
该答案的其余部分是对关心波兰语的读者的奖励材料。
say seq-range-gist (0, 1, 2, 3), ^3
显示:
0 => 0
1 => 1
2 => 2
...
1 => 1
2 => 2
哎呀 而且,即使对的数量超过了头和尾的总和,所以至少我们没有得到重复的行,使用head, ..., tail
只消除一两个元素的方法仍然毫无意义。让我们更改子正文中的最后一条语句以消除这些问题:
join "\n",
@pairs < $head + $tail + 3 # Of course, the 3 is a bit arbitrary
?? @pairs».&gist
!! (@pairs.head($head)».&gist, '...', @pairs.tail($tail)».&gist)
接下来,如果子程序在没有范围或要旨的情况下进行了一些有用的操作,那就很好了。我们可以通过为@range
和&gist
参数提供适当的默认值来解决此问题:
sub seq-range-gist (
@seq,
@range = @seq.is-lazy ?? ^100 !! ^@seq,
:&gist = { .gist }
) {
如果@seq
是不 懒,那么@range
默认为全方位的@seq
。如果@seq
是无限的(在这种情况下它也是惰性的),那么最多100个默认值也可以。但是,如果@seq
懒惰但产生的定义值少于100怎么办?为了解决这种情况,我们.grep: *.value.defined
在@pairs
声明后追加:
my @pairs = @seq.pairs[@range].grep: *.value.defined;
另一个简单的改进是可选的头和尾参数,从而得出最终的解决方案:
sub seq-range-gist (
@seq,
@range = @seq.is-lazy ?? ^100 !! ^@seq,
:$head = 3,
:$tail = 2,
:&gist = { .gist }
) {
my @pairs = @seq.pairs[@range].grep: *.value.defined;
join "\n",
@pairs <= $head + $tail + 2
?? @pairs».&gist
!! (@pairs.head($head)».&gist, '...', @pairs.tail($tail)».&gist)
}