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


9

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

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

谢谢。


@DanBron谢谢您的评论。我刚刚对原始帖子进行了编辑和阐述。
拉尔斯·马尔姆斯汀

Answers:


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个元素,.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-gistsub 主体中的“方法”调用现在.&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)
}

最小的解决方案工作得很好,它也是习惯用法。在我的解决方案中,我不得不求助于'flag'变量来估计...导致它看起来更像C程序的部分。因此,这确实回答了我的问题的两个部分。至于“综合”解决方案,确实看起来有些吓人。
拉尔斯·马尔姆斯汀

感谢您的反馈并接受我的@LarsMalmsteen答复。就是说,我已经完全重写了我的答案,并认为它要好得多。我放弃了“全面”解决方案-我已经远远地摆脱了杂草!-但我也完全重写了“最小解决方案”和随附的说明。我主要是为其他后来的读者这样做的,但您可能会从阅读新答案中获得一些价值。
raiph

7

您可以跳过第一的N值的任何 IterableSequenceskip

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

如果您未指定数字,它将仅跳过一个元素。


skip似乎与0号指数(A0)遗骸只删除输出中,即该元素。我已经尝试过@seq:delete,它只是将第0个元素替换为(Any)
Lars Malmsteen,

确实。该skip会只是充当如果跳过的元素不存在。这可能是您想要的,也可能不是:-)
伊丽莎白·马蒂森

当我将它们skip放在中间时,它会显示为:for @seq[^10].skip(0).kv实际上不会跳过第0个元素,并且如果我将参数设为skip1或2 也没有关系,只会进一步扭曲输出。我需要一种实用的方法来从地面上删除第0个元素。
拉尔斯·马尔姆斯汀

1
也许for @seq[^10].kv.skip(2)您在找什么?
伊丽莎白·马蒂森

是的,可以完成工作。实际上,我尝试将the放在skipafter之后,.kv但使用的参数不是2,所以它不起作用。谢谢您的解决方案。
拉尔斯·马尔姆斯汀

7

这可能更惯用:

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

您无需在序列中使用词汇变量;任一Whatever占位符变量可以安全序列内使用。然后,您可以简单地选择要打印的序列的元素。哪个返回«(0 1 2 3)(7 8 9 10)␤»


谢谢你的回答。该whatever操作员refreshening但该系列/序列输出不解决的主要问题。我想打印在数学texbook上看到的系列,即...介于两者之间的符号。
拉尔斯·马尔姆斯汀

@LarsMalmsteen,好的,我将编辑它
jjmerelo
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.