我正试图在Erlang中学习递归,而我正在写一本书。 但是当遇到列表并仅返回重复元素的问题时,我正在撞墙。 我尝试编写一个只返回唯一元素的函数,然后将它们从原始列表中删除。
adjacent_dups(L) -> L -- uniques(L).
uniques([]) -> [];
uniques([H|T]) -> [H | [X || X <- uniques(T), X /= H]].
但是当列表结构不合理时,这将无法给出正确的结果。
L = [7,3,4,3]
我的代码将返回
adjacent_dups([7,3,4,3]) -> 3
我怎样才能获得
adjacent_dups([7,3,4,3]) -> []
答案 0 :(得分:5)
在函数头中使用模式匹配来查找相邻的相同值:
adjacent_dups(L) ->
adjacent_dups(L, #{}).
adjacent_dups([], Acc) ->
maps:keys(Acc);
adjacent_dups([H,H|T], Acc) ->
adjacent_dups(T,maps:put(H,H,Acc));
adjacent_dups([_|T], Acc) ->
adjacent_dups(T, Acc).
第一个函数adjacent_dups/1
是要导出的。其余的adjacent_dups/2
是辅助函数。
adjacent_dups/1
函数创建一个空映射以传递给adjacent_dups/2
作为累加器的初始值。递归函数通常使用累加器。
adjacent_dups/2
的第一个句子处理传入列表已用尽或开始时为空的情况。在这种情况下,我们检索累加器映射的键;这些是我们相邻的价值观。
adjacent_dups/2
的第二个子句使用模式匹配处理相邻值的大小写。在这种情况下,我们将值作为键和值添加到累加器映射,并使用列表的尾部递归调用自己。使用地图可以消除最终结果中的重复。
adjacent_dups/2
的最后一个句子处理一个值没有相邻值的情况;它只是使用列表尾部和未修改的累加器进行递归调用。
答案 1 :(得分:4)
如果您只想要相邻的重复项,可以尝试从列表中成对匹配它们。这是一个让你入门的天真解决方案。它假设重复项只能成对出现(例如,连续三个):
adjacent_dups([]) -> [];
adjacent_dups([A,A|Tail]) -> [A|adjacent_dups(Tail)];
adjacent_dups([_Head|Tail]) -> adjacent_dups(Tail).
如果我们更多地考虑它,我们可能会意识到我们可以以同样的方式处理三元组。通过使这种情况只消耗第一个值并将其他两个返回,我们实际上可以使它足够通用,即使连续存在多于两个。观看魔术:
adjacent_dups([]) -> [];
adjacent_dups([A,A,A|Tail]) -> adjacent_dups([A,A|Tail]);
adjacent_dups([A,A|Tail]) -> [A|adjacent_dups(Tail)];
adjacent_dups([_Head|Tail]) -> adjacent_dups(Tail).
这是输出:
adjacent_dups([1,1,1,1,2,3,4,55,55,6,7,8,8,8,1]).
[1,55,8]