在Raku中简洁地打印数学系列

数学序列,例如以此处表示为数组的连续序列:

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-是否可以使此代码更加惯用?

谢谢。

baitu1987 回答:在Raku中简洁地打印数学系列

您可以使用Iterable跳过任何 Sequenceskip上的前N个值:

for (^5).skip(3) {
    .say
}
# 3
# 4

如果您未指定数字,则只会跳过一个元素。

,

这可能更惯用:

my @seq = 0,*+1 ... *;
say @seq[^4],@seq[7..10]

您无需在序列中使用词汇变量; Whateverplaceholder 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)
}
本文链接:https://www.f2er.com/3132729.html

大家都在问