在 Raku 列表中查找相等元素的连续序列

Lar*_*een 9 sequence raku

我想在列表中找到相等元素(例如长度为 2)的连续序列

my @s = <1 1 0 2 0 2 1 2 2 2 4 4 3 3>;
say grep {$^a eq $^b}, @s;

# ==> ((1 1) (2 2) (4 4) (3 3))
Run Code Online (Sandbox Code Playgroud)

这段代码看起来不错,但是当在2的序列之后添加另外2 2 2一个2或从中删除一个2时,它会显示Too few positionals passed; expected 2 arguments but got 1如何修复它?请注意,我试图在不使用for循环的情况下找到它们,即我试图尽可能地使用功能代码来找到它们。

可选:在粗体打印部分:

<1 1 0 2 0 2 1 2 2 2 4 4 3 3>

2 2可以看到多个序列。如何打印它们被看到的次数?喜欢:

((1 1) (2 2) (2 2) (4 4) (3 3))
Run Code Online (Sandbox Code Playgroud)

rai*_*iph 9

您的输入中有偶数个元素:

say elems <1 1 0 2 0 2 1 2 2 2 4 4 3 3>; # 14
Run Code Online (Sandbox Code Playgroud)

您的grep块每次消耗两个元素:

{$^a eq $^b}
Run Code Online (Sandbox Code Playgroud)

因此,如果您添加或删除一个元素,当块在最后剩下的单个元素上运行时,您将收到错误。


有很多方法可以解决您的问题。

但是您还询问了允许重叠的选项,例如,(2 2)2 2 2遇到序列时,您会得到两个子列表。而且,以类似的方式,您可能希望看到两个匹配项,而不是零,输入如下:

<1 2 2 3 3 4>
Run Code Online (Sandbox Code Playgroud)

因此,我也将专注于处理这些问题的解决方案。

尽管解决额外问题的解决方案空间变窄,但仍然有很多方法可以从功能上表达解决方案。


一种只是在你的末尾附加更多代码的方法:

my @s = <1 1 0 2 0 2 1 2 2 2 4 4 3 3>;
say grep {$^a eq $^b}, @s .rotor( 2 => -1 ) .flat
Run Code Online (Sandbox Code Playgroud)

.rotor方法将列表转换为子列表的列表,每个子列表的长度都相同。例如,say <1 2 3 4> .rotor: 2显示((1 2) (3 4)). 如果长度参数是一对,则键是长度,值是开始下一对的偏移量。如果偏移量为负,您将获得子列表重叠。从而say <1 2 3 4> .rotor: 2 => -1显示((1 2) (2 3) (3 4))

.flat方法“扁平化”了它的调用者。例如,say ((1,2),(2,3),(3,4)) .flat显示(1 2 2 3 3 4).

编写上述解决方案的一种可能更易读的方法是省略flatand use.[0].[1]索引到由 返回的子列表rotor

say @s .rotor( 2 => -1 ) .grep: { .[0] eq .[1] }
Run Code Online (Sandbox Code Playgroud)

另请参阅 Elizabeth Mattijsen 对适用于任何子列表大小的另一种变体的评论。


如果您需要更通用的编码模式,您可以编写如下内容:

say @s .pairs .map: { .value xx 2 if .key < @s - 1 and [eq] @s[.key,.key+1] }
Run Code Online (Sandbox Code Playgroud)

.pairs列表上方法返回一个对的列表,每对对应于其调用者列表中的每个元素。的.key各对是在调用者列表中的元素的索引; 的.value是该元素的值。

.value xx 2本来可以写的.value, .value。(见xx。)

@s - 1@s负 1 中的元素数。

[eq][eq] list是一个减少


如果您需要文本模式匹配来决定什么构成连续的相等元素,您可以将输入列表转换为字符串,使用生成匹配列表的匹配副词之一进行匹配,然后从结果匹配列表映射到您想要的结果。匹配重叠(例如使用2 2 2结果:((2 2) (2 2)):ov

say @s .Str .match( / (.) ' ' $0 /, :ov ) .map: { .[0].Str xx 2 }
Run Code Online (Sandbox Code Playgroud)

  • `我的 $size = 2; 说 &lt;1 1 0 2 0 2 1 2 2 2 4 4 3 3&gt;.rotor( $size =&gt; -$size + 1).grep: { [eq] $_ }` # ((1 1) (2 2 ) (2 2) (4 4) (3 3)) 您只需要针对不同长度的序列调整 `$size` 即可。 (3认同)

Hol*_*lli 5

蒂姆托迪!

这是使用gather/的迭代方法take

say gather for <1 1 0 2 0 2 1 2 2 2 4 4 3 3> { 
    state $last = ''; 
    take ($last, $_) if $last == $_; 
    $last = $_; 
};

# ((1 1) (2 2) (2 2) (4 4) (3 3))
Run Code Online (Sandbox Code Playgroud)