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

时间:2019-12-10 11:49:16

标签: 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))

此代码看起来不错,但是在2 2 2的序列之后添加了另外一个 2 或从中删除了一个 2 时,它表示{{ 1}}怎么解决?请注意,我尝试不使用Too few positionals passed; expected 2 arguments but got 1循环来查找它们,即,尝试使用功能代码来尽可能地查找它们。

可选:在粗体显示部分:

for 2 2 2 <1 1 0 2 0 2 1

可以看到

4 4 3 3>的多个序列。如何打印它们被看到的次数?喜欢:

2 2

2 个答案:

答案 0 :(得分:8)

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

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))。如果length参数是一对,则键是长度,值是开始下一个对的偏移量。如果偏移量为负,则子列表重叠。因此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]中的[eq] listreduction


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

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

答案 1 :(得分:5)

TIMTOWDI!

这是一种使用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))