数学级数,例如以此处表示为数组的连续序列:
my @seq = my $a=0, {++$a} ... *;
for @seq[^10].kv {state $f=0; ($^k < 4 or $^k > 7) ?? say "a$^k = " ~ $^v !! (say "..." if $f ne 1; $f=1) };
Run Code Online (Sandbox Code Playgroud)
印刷品:
a0 = 0
a1 = 1
a2 = 2
...
a8 = 8
a9 = 9
Run Code Online (Sandbox Code Playgroud)
我的问题:1-是否有一种简单的方法可以只删除第一个元素,即a0 = 0
从打印输出中删除?
2-可以使此代码更惯用吗?
谢谢。
您可以跳过第一的N值的任何 Iterable
或Sequence
有skip
:
for (^5).skip(3) {
.say
}
# 3
# 4
Run Code Online (Sandbox Code Playgroud)
如果您未指定数字,它将仅跳过一个元素。
这可能更惯用:
my @seq = 0, *+1 ... *;
say @seq[^4], @seq[7..10]
Run Code Online (Sandbox Code Playgroud)
您无需在序列中使用词汇变量;任一Whatever
或占位符变量可以安全序列内使用。然后,您可以简单地选择要打印的序列的元素。哪个返回«(0 1 2 3)(7 8 9 10)?»
让我们从一个非常简单的打印序列要点的解决方案开始。它不涉及您添加到问题中的具体细节,但它是一个很好的起点:
\n\nsub seq-range-gist ( @seq ) {\n my @pairs = @seq.pairs;\n join "\\n", @pairs.head(3)\xc2\xbb.gist, \'...\', @pairs.tail(2)\xc2\xbb.gist\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n与 不同.kv
,它将其调用者转换为 形式key1, value1, key2, value2, key3, value3, ...
,即 6 个元素,如果其调用者包含 3 个元素,.pairs
则将其调用者转换为形式key1 => value1, key2 => value2, key3 => value3, ...
。
我使用.pairs
而不是.kv
部分,因为这意味着我可以\xc2\xbb.gist
稍后在代码中使用来轻松地key1 => value1
为每个元素获得良好的显示。我们将在下面修改它,但这是一个很好的惯用开始。
和.head
调用.tail
是从调用列表创建第一个和最后 N 个元素的小列表的惯用方法(前提是它不是懒惰的;稍后会详细介绍)。
给定这个初始解决方案,say seq-range-gist (0,1 ... Inf)[^10]
显示:
0 => 0\n1 => 1\n2 => 2\n...\n8 => 8\n9 => 9\n
Run Code Online (Sandbox Code Playgroud)\n\n接下来,我们希望能够“从打印输出中仅删除第一个元素......”。不幸的say seq-range-gist (0,1 ... Inf)[1..9]
是显示:
0 => 1\n1 => 2\n2 => 3\n...\n7 => 8\n8 => 9\n
Run Code Online (Sandbox Code Playgroud)\n\n我们希望左侧的数字=>
保留原始序列的编号。为了实现这一点,我们将基础序列从我们想要提取的范围中分离出来。我们添加第二个参数/参数@range
,并附加到[@range]
子文件的第二行:
sub seq-range-gist ( @seq, @range ) {\n my @pairs = @seq.pairs[@range];\n
Run Code Online (Sandbox Code Playgroud)\n\n现在我们可以编写say seq-range-gist (0,1 ... Inf), 1..9
显示:
1 => 1\n2 => 2\n3 => 3\n...\n8 => 8\n9 => 9\n
Run Code Online (Sandbox Code Playgroud)\n\n在您的问题中,您使用的是格式aINDEX = VALUE
而不是INDEX => VALUE
. 为了允许自定义要点,我们添加第三个&gist
例程参数/参数并调用它而不是内置.gist
方法:
sub seq-range-gist ( @seq, @range, :&gist ) {\n my @pairs = @seq.pairs[@range];\n join "\\n", @pairs.head(3)\xc2\xbb.&gist, \'...\', @pairs.tail(2)\xc2\xbb.&gist\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n请注意 sub 主体中的“方法”调用seq-range-gist
现在是.&gist
,而不是.gist
。该语法.&foo
调用sub &foo
(通常通过只编写 来调用foo
),将 the 左侧的调用者.
作为 a传递$_
参数传递给 sub。
另请注意,我已&gist
通过在参数前面添加一个命名参数来将其命名为:
.
所以现在say seq-range-gist (0,1 ... Inf), 1..9, gist => { "a{.key} = {.value}" }
显示:
a1 = 1\na2 = 2\na3 = 3\n...\na8 = 8\na9 = 9\n
Run Code Online (Sandbox Code Playgroud)\n\n对于关心润色的读者来说,这个答案的其余部分是额外的材料。
\n\nsay seq-range-gist (0, 1, 2, 3), ^3
显示:
0 => 0\n1 => 1\n2 => 2\n...\n1 => 1\n2 => 2\n
Run Code Online (Sandbox Code Playgroud)\n\n哎呀。即使有比头和尾加起来更多的对,所以至少我们没有得到重复的行,使用head, ..., tail
仅删除一两个元素的方法仍然是没有意义的。让我们更改子正文中的最后一条语句以消除这些问题:
join "\\n",\n @pairs < $head + $tail + 3 # Of course, the 3 is a bit arbitrary\n ?? @pairs\xc2\xbb.&gist\n !! (@pairs.head($head)\xc2\xbb.&gist, \'...\', @pairs.tail($tail)\xc2\xbb.&gist)\n
Run Code Online (Sandbox Code Playgroud)\n\n接下来,如果在没有范围或要点的情况下调用该子函数,可以做一些有用的事情,那就太好了。我们可以通过给出@range
和来解决这个问题&gist
参数提供合适的默认值来解决这个问题:
sub seq-range-gist (\n @seq,\n @range = @seq.is-lazy ?? ^100 !! ^@seq,\n :&gist = { .gist }\n) {\n
Run Code Online (Sandbox Code Playgroud)\n\n如果@seq
不是偷懒 ,那么默认@range
是全范围的@seq
。如果@seq
是无限的(在这种情况下它也是惰性的),那么默认值最多 100就可以了。但是,如果@seq
是惰性的但生成的定义值少于 100 个怎么办?为了涵盖这种情况,我们附加.grep: *.value.defined
到@pairs
声明中:
my @pairs = @seq.pairs[@range].grep: *.value.defined;\n
Run Code Online (Sandbox Code Playgroud)\n\n另一个简单的改进是可选的头部和尾部参数,从而形成最终的完善解决方案:
\n\nsub seq-range-gist (\n @seq,\n @range = @seq.is-lazy ?? ^100 !! ^@seq,\n :$head = 3,\n :$tail = 2,\n :&gist = { .gist }\n) {\n my @pairs = @seq.pairs[@range].grep: *.value.defined;\n join "\\n",\n @pairs <= $head + $tail + 2\n ?? @pairs\xc2\xbb.&gist\n !! (@pairs.head($head)\xc2\xbb.&gist, \'...\', @pairs.tail($tail)\xc2\xbb.&gist)\n}\n
Run Code Online (Sandbox Code Playgroud)\n