您可以使用Iterable
跳过任何 Sequence
或skip
上的前N个值:
for (^5).skip(3) {
.say
}
# 3
# 4
如果您未指定数字,则只会跳过一个元素。
,
这可能更惯用:
my @seq = 0,*+1 ... *;
say @seq[^4],@seq[7..10]
您无需在序列中使用词汇变量; Whatever
或placeholder variables都可以在序列中安全使用。然后,您可以简单地选择要打印的序列的元素。
返回«(0 1 2 3)(7 8 9 10)»
,
准系统解决方案
让我们从打印序列要点的非常简单的解决方案开始。它不会处理您添加到问题中的具体信息,但这是一个很好的起点:
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个元素,则转换为6个元素,.pairs
将其请求者的形式转换为key1 => value1,key2 => value2,key3 => value3,...
的形式。
我使用.pairs
而不是.kv
的部分原因是,这意味着我稍后可以在代码中使用».gist
来轻松地为每个元素获得漂亮的key1 => value1
显示。我们将在下面进行修改,但这是一个很好的习惯用法。
.head
和.tail
调用是一种惯用的方法,用于从主列表中创建前N个元素的最后一个小列表(前提是它不偷懒;更多有关mo的内容)。 / p>
鉴于此初始解决方案,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
子正文中的“方法”调用现在是.&gist
,而不是.gist
。语法.&foo
调用 sub &foo
(通常仅通过写foo
来调用),将调用者传递到.
的左侧作为该子项的$_
自变量。
还要注意,我在&gist
参数前面加上了:
。
所以现在say seq-range-gist (0,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)
接下来,如果在没有范围或要旨的情况下调用sub会做一些有用的事情,那就太好了。我们可以通过为@range
和&gist
参数提供适当的默认值来解决此问题:
sub seq-range-gist (
@seq,@range = @seq.is-lazy ?? ^100 !! ^@seq,:&gist = { .gist }
) {
如果@seq
不是 lazy,则@range
默认为@seq
的整个范围。如果@seq
是 infinite (在这种情况下它也是惰性的),则最多100 的默认值是可以的。但是,如果@seq
是惰性的,但产生的定义值少于100怎么办?为了解决这种情况,我们将.grep: *.value.defined
附加到@pairs
声明中:
my @pairs = @seq.pairs[@range].grep: *.value.defined;
另一个简单的改进是可选的头和尾参数,从而得到最终的解决方案:
sub seq-range-gist (
@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)
}