在列表 Raku 中查找相等元素的连续序列
Finding the contiguous sequences of equal elements in a list 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 或者当一个 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))
您输入的元素个数为偶数:
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>
所以我也将专注于处理这些问题的解决方案。
尽管为了处理额外的问题缩小了解决方案space,但仍然有很多方法可以从功能上表达解决方案。
一种方法是在你的末尾附加更多代码:
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 "flattens" 其法师。例如,say ((1,2),(2,3),(3,4)) .flat
显示 (1 2 2 3 3 4)
.
编写上述解决方案的一种可能更具可读性的方法是省略 flat
并使用 .[0]
和 .[1]
索引到 [=31 返回的子列表中=]:
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 returns 一对列表,每对对应于其调用列表中的每个元素。每对的.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( / (.) ' ' [=16=] /, :ov ) .map: { .[0].Str xx 2 }
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))
我想在列表中找到相等元素(例如长度为 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 或者当一个 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))
您输入的元素个数为偶数:
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>
所以我也将专注于处理这些问题的解决方案。
尽管为了处理额外的问题缩小了解决方案space,但仍然有很多方法可以从功能上表达解决方案。
一种方法是在你的末尾附加更多代码:
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 "flattens" 其法师。例如,say ((1,2),(2,3),(3,4)) .flat
显示 (1 2 2 3 3 4)
.
编写上述解决方案的一种可能更具可读性的方法是省略 flat
并使用 .[0]
和 .[1]
索引到 [=31 返回的子列表中=]:
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 returns 一对列表,每对对应于其调用列表中的每个元素。每对的.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( / (.) ' ' [=16=] /, :ov ) .map: { .[0].Str xx 2 }
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))