【问题标题】:Return adjacent duplicates in Erlang在 Erlang 中返回相邻的重复项
【发布时间】:2015-09-29 14:33:00
【问题描述】:

我正在尝试学习 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]) -> [] 

【问题讨论】:

  • 这是未指定的:您期望的输出是什么,例如[2,3,3,4,1,1] 结果如何排序。 [6,4,4,4,3,1,1,1,1] 应该发生什么?那么 [1,2,3,3,4,3,3] 呢?
  • 这实际上与 Dave Thomas 在去年 ElixirConf 的演讲中提到的问题非常相似。以下是演讲相关部分的链接:youtu.be/5hDVftaPQwY?t=12m18s

标签: recursion erlang


【解决方案1】:

在函数头中使用模式匹配来查找相邻的相同值:

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 的最后一个子句处理一个值没有相邻值的情况;它只是使用列表的尾部和未修改的累加器进行递归调用。

【讨论】:

  • 答案已经解释了地图允许我们从结果中消除重复。使用它们意味着不需要检查值是否已经被看到;相反,只需将其添加到地图中。如果我们使用列表来代替,我们必须在每次累加器插入时遍历列表以查看它是否已经存在,如果已经存在则不要添加它。
  • 取决于规范是什么,问题中没有明确说明问题。此解决方案仅以任意顺序输出每个重复值一次
  • 标题要求一件事,问题要求另一件事。
  • 问题是地图有O(log(N))的访问时间。结果并不比lists:usort好,但更复杂
【解决方案2】:

如果您只想要相邻的重复项,您可以尝试从列表中对它们进行模式匹配。这是一个简单的解决方案,可以帮助您入门。它假设重复项只能成对找到(例如,从不连续三个):

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]

【讨论】:

    猜你喜欢
    • 2015-11-29
    • 1970-01-01
    • 1970-01-01
    • 2018-11-28
    • 2016-02-05
    • 2023-01-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多