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


9

我想在列表中找到相等元素(例如,长度为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时,它说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))

Answers:


9

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

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方法将列表转换为子列表的列表,每个子列表的长度相同。例如,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方法 “压扁”其倡导者。例如,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列表上方法返回一个成对的列表,每对对应于其调用列表中的每个元素。的.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 }

它工作得很好。当我加2 2 s来制作序列时2 2 2 2(2 2)它会按预期打印3 s。从来没有听说过该方法,rotor我最初想出了该squish方法,并检查了它是否具有诸如以下的功能或参数,@s.squish(:length 2, :multiple_instances yes)但它没有此类功能,因此不适合该任务。与相比squishrotor 似乎很合适。实际上,对于这种类型的操作,它甚至可能是最合适的一种。
拉尔斯·马尔姆斯汀

3
my $size = 2; say <1 1 0 2 0 2 1 2 2 2 4 4 3 3>.rotor( $size => -$size + 1).grep: { [eq] $_ }#(((1 1)(2 2)(2 2)(4 4)(3 3))您只需要调整$size序列的不同长度即可。
伊丽莎白·马蒂森

嗨,@ LarsMalmsteen。如果您认为rotor我添加的两个替代方案削弱或增强了我的答案,请请LMK 。
raiph

rotor解决方案的改进版本即say @s.rotor(2=>-1).grep:{.[0]eq.[1]}受欢迎,因为它既较短(减少3到5个字符,具体取决于如何计算空格),而且看起来仍然不错。rotor也欢迎不使用该方法的通用版本,因为它们显示了如何使用xx和这样的怪癖:ov。因此,这个问题已得到很好的解决:)
Lars Malmsteen

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))

谢谢你的回答。就其本身而言,这看起来还不错。该take ($last, $_)部分是有关gather and take二重奏用法的一个很好的例子。
拉尔斯·马尔姆斯汀
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.