您的输入中有偶数个元素:
say elems <1 1 0 2 0 2 1 2 2 2 4 4 3 3>; # 14
您的 grep 块每次消耗两个元素:
{$^a eq $^b}
所以如果你添加或删除一个元素,当块在最后剩下的单个元素上运行时,你会得到错误。
有很多方法可以解决您的问题。
但是您还询问了允许重叠的选项,例如,当遇到序列 2 2 2 时,您会得到两个 (2 2) 子列表。而且,以类似的方式,您可能希望看到两个匹配,而不是零,输入如下:
<1 2 2 3 3 4>
所以我也会专注于解决这些问题的解决方案。
尽管解决额外问题的解决方案空间变窄了,但仍有很多方法可以从功能上表达解决方案。
一种只是在你的末尾附加更多代码的方法:
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
.rotor method 将列表转换为子列表的列表,每个子列表的长度相同。例如,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 method“扁平化”它的调用者。例如,say ((1,2),(2,3),(3,4)) .flat 显示 (1 2 2 3 3 4)。
编写上述解决方案的一种可能更具可读性的方法是省略flat,并使用.[0] 和.[1] 来索引rotor 返回的子列表:
say @s .rotor( 2 => -1 ) .grep: { .[0] eq .[1] }
另请参阅 Elizabeth Mattijsen 的评论,了解可概括任何子列表大小的另一种变体。
如果您需要更通用的编码模式,您可以编写如下内容:
say @s .pairs .map: { .value xx 2 if .key < @s - 1 and [eq] @s[.key,.key+1] }
.pairs method on a list 返回一个对列表,每对对应于其调用者列表中的每个元素。每对的.key 是调用者列表中元素的索引; .value 是元素的值。
.value xx 2 可以写成.value, .value。 (见xx。)
@s - 1 是@s 中的元素个数减1。
[eq] list 中的[eq] 是reduction。
如果您需要文本模式匹配来确定连续相等元素的构成,您可以将输入列表转换为字符串,使用生成匹配列表的匹配副词之一进行匹配,然后从结果匹配列表中映射达到您想要的结果。为了匹配重叠(例如2 2 2 导致((2 2) (2 2)) 使用:ov:
say @s .Str .match( / (.) ' ' $0 /, :ov ) .map: { .[0].Str xx 2 }