我想在列表中找到相等元素(例如长度为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
答案 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] list
是reduction。
如果需要文本模式匹配来确定什么构成连续的相等元素,则可以将输入列表转换为字符串,使用生成匹配列表的匹配副词之一与之匹配,然后从匹配结果列表中进行映射达到您想要的结果。要匹配重叠(例如,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))