数学级数,例如以此处表示为数组的连续序列:
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) };
打印:a0 = 0
a1 = 1
a2 = 2
...
a8 = 8
a9 = 9
1-是否有一种简单的方法从打印输出中仅删除第一个元素,即a0 = 0
?2-可以使此代码更惯用吗?
最佳答案
准系统解决方案
让我们从一个非常简单的解决方案开始,该解决方案用于打印序列的要点。它不会处理您添加到问题中的细节,但这是一个很好的起点:
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的内容)。在此初始解决方案的基础上,
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
会调用子&foo
(通常仅通过编写foo
来调用),并将.
左侧的调用者作为$_
参数传递给子。还要注意,我已经在
&gist
前面加上了:
,从而将say seq-range-gist (0,1 ... Inf), 1..9, gist => { "a{.key} = {.value}" }
参数命名为一个。因此,现在
say seq-range-gist (0, 1, 2, 3), ^3
显示:a1 = 1
a2 = 2
a3 = 3
...
a8 = 8
a9 = 9
上光油
该答案的其余部分是对关心波兰语的读者的奖励 Material 。
head, ..., tail
显示:0 => 0
1 => 1
2 => 2
...
1 => 1
2 => 2
哎呀。而且即使对的数量超过了头和尾的总和,所以至少我们没有得到重复的行,但使用
@range
方法只消除一个或两个元素仍然是毫无意义的。让我们更改子正文中的最后一条语句以消除这些问题: join "\n",
@pairs < $head + $tail + 3 # Of course, the 3 is a bit arbitrary
?? @pairs».&gist
!! (@pairs.head($head)».&gist, '...', @pairs.tail($tail)».&gist)
接下来,如果子程序在没有范围或要旨的情况下进行了一些有用的操作,那就很好了。我们通常可以通过为
&gist
和@seq
参数提供适当的默认值来解决此问题:sub seq-range-gist (
@seq,
@range = @seq.is-lazy ?? ^100 !! ^@seq,
:&gist = { .gist }
) {
如果
@range
不是lazy,则@seq
默认为@seq
的整个范围。如果@seq
是无限的(在这种情况下它也是惰性的),则默认100以内是可以的。但是,如果.grep: *.value.defined
是惰性的,但产生的定义值小于100,该怎么办?为了解决这种情况,我们将@pairs
附加到ojit_code声明中: 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)
}
关于sequence - 在Raku中简洁地打印数学系列,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/58779757/