如何处理带有 >> 和 return 平面数组的嵌套数组?

How to handle nested array with >> and return a flat array?

我想知道 Raku 中是否有一种简洁的方法来处理嵌套数组(数组的数组)和 压平结果?当转换平面数组时 >>. 很方便,但如果我想 return 数组并且结果应该是平面的,Raku 中可以使用什么结构?

grammar g {
    rule port       { <pnamelist> + %% ","}
    token pnamelist { <id> +  }
    token id        { \w }
}

class a {
    method port ($/)      { make  $<pnamelist>>>.made  }
    method pnamelist ($/) { make  $<id>>>.made  }
    method id ($/ )       { make $/.Str }
}

my $r = g.parse("ab,cd", :rule('port'), :actions(a) ).made; 

say $r; # [[a b] [c d]]

上面的代码片段输出 [[a b] [c d]],但我真正想要的是 [a b c d]。是否有一种简洁的方法来重写 make $<pnamelist>>>.made 以便它遍历数组 $<pnamelist> 并将每个元素 .made 收集在一个平面列表中,然后为 ``make` 输入什么?

make $<pnamelist>.map(*.made.Slip)

当您 slip map 中的值列表时,它们会变平。

在很多情况下使用 >>. 很好,但我个人更喜欢 .map,因为它允许更大的灵活性。

TL;DR 使用位置下标展开。对于您的示例,将 [*;*][**] 附加到 $<pnamelist>>>.made。您会得到与 Liz 的解决方案相同的结果。

为什么要使用这个解决方案?

Liz 说得对 map 和亲戚 (for, deepmap, duckmap, nodemap, and tree) 更灵活,至少在集体上,将它们与 .Slip 结合起来可能只是门票。

但我经常发现使用这些工具和其他工具(包括 hypers)在认知上更简单,可以创建任何数据结构,而无需担心 .Sliping,然后在最后将结果展平只需附加 [*;*...][**],如下所述。

最后但同样重要的是,它简单明了:

method port ($/) { make $<pnamelist>>>.made[**] }
                                           ^^^^

[*;*...]

深度展平 N 个级别

的一般方法。

第一个Whatever剥离外层数组;每个额外的 Whatever,由 ; 分隔,剥离另一个内部嵌套层。对于您当前的示例,两个 Whatever 可以完成工作:

method port ($/) { make $<pnamelist>>>.made[*;*] }
                                           ^^^^^

这会产生与 Liz 的解决方案相同的结果:

(a b c d)

如果你希望最终结果有一个外部数组,只要在你认为合适的地方添加到最终结果即可,例如:

method port ($/) { make [ $<pnamelist>>>.made[**] ] }

推土机 [**]

如果你想推土机嵌套array/list,剥离所有嵌套,无论有多深,你可以写的 *; 比你可能需要的多。任何额外的东西都不会产生任何影响。

但是推土机的愿望是很自然的,而且经常出现,所以有一个操作可以做到这一点而不需要像“只写很多 *;”这样的骇人听闻的概念是有意义的。

因此,@Larry 在大约十年前指定了这样一个 bulldozing 操作也就不足为奇了。使用 HyperWhatever (**) 作为索引值,这与 Raku 的其他感觉非常一致。

但尝试一下:

method port ($/) { make $<pnamelist>>>.made[**] }
                                           ^^^^

当前产量:

HyperWhatever in array index not yet implemented. Sorry.

幸运的是,可以很容易地“伪造”它:

sub postfix:< [**] > (\lhs) { gather lhs.deepmap: *.take }

后缀正文来自

有了这个,然后将 [*;*] 更改为 [**] 将适用于您的示例,但无论其左侧嵌套的深度如何,都将继续工作。

并且假设数组索引中的 HyperWhatever 有朝一日作为内置实现,人们将能够删除后缀定义,并且使用它的任何代码在没有它的情况下也能正常工作——而且,大概会得到一个加速。