elixir-lang在列表中查找非重复元素

时间:2015-11-06 13:23:20

标签: elixir

我试图从列表中找到非重复值,例如

原始列表:

iex> list = [2, 3, 4, 4, 5, 6, 6, 6, 7, 8, 8, 8, 9, 9, 10, 10, 10]
[2, 3, 4, 4, 5, 6, 6, 6, 7, 8, 8, 8, 9, 9, 10, 10, 10]

iex> unique = Enum.uniq(list)
[2, 3, 4, 5, 6, 7, 8, 9, 10]

iex> nondupes = unique -- Enum.uniq(list -- unique)
[2, 3, 5, 7]

结果:[2,3,5,7]

我想知道在elixir / erlang中是否有更好的方法来实现这个目标

4 个答案:

答案 0 :(得分:10)

对于大数据可能更快的另一种方法(不一定更好)是从元素到其计数构建映射并选择count为1的那些:

O(n * log(n))

这应该有运行时O(n ^ 2)而不是你的解决方案所需的{{1}}(如果整个输入已经是唯一的,则减法应该是二次的。)

答案 1 :(得分:1)

以下是 José Valim's suggestion 的实现,虽然该建议是在 Enum.frequencies/1 可用之前提出的,但我认为 arpit's version 更简单、更清晰。

list
|> Enum.reduce({MapSet.new(), MapSet.new()}, fn item, {seen, uniq} ->
  case MapSet.member?(seen, item) do
    true -> {seen, MapSet.delete(uniq, item)}
    false -> {MapSet.put(seen, item), MapSet.put(uniq, item)}
  end
end)
|> elem(1)
|> MapSet.to_list()

答案 2 :(得分:0)

<强> REDO

(正如Paweł指出的那样,我没有回答这个问题,而只是解决了这个问题。所以我在下面过火了。)

这是一个纯粹的递归,单遍,仅匹配的方法:

-module(nondupes).
-export([leave_uniques/1]).

leave_uniques(L) ->
    lists:reverse(lu(lists:sort(L))).

lu(L = [H,H|_]) -> lu(L, [], dupe);
lu([H|T])       -> lu(T, [H], solo).

lu([H,H], A, dupe)           -> A;
lu([_,H], A, dupe)           -> [H|A];
lu([H,H], A, solo)           -> A;
lu([P,H], A, solo)           -> [P,H|A];
lu([H | T = [H|_]], A, dupe) -> lu(T, A, dupe);
lu([_ | T], A, dupe)         -> lu(T, A, solo);
lu([H | T = [H|_]], A, solo) -> lu(T, A, dupe);
lu([P | T], A, solo)         -> lu(T, [P|A], solo).

如果过去的经验是任何判断,它可能在大型列表上比列表/集合减法更高效 - 但过去的经验也告诉我,大多数时候表现真的不是一个问题。无论如何,这有点令人愉快。

使用:

2> nondupes:leave_uniques([2, 3, 4, 4, 5, 6, 6, 6, 7, 8, 8, 8, 9, 9, 10, 10, 10]).
[2,3,5,7]

答案 3 :(得分:0)

注意:使用elixir 1.10,可以使用frequencies函数。

[2, 3, 4, 4, 5, 6, 6, 6, 7, 8, 8, 8, 9, 9, 10, 10, 10] 
|> Enum.frequencies 
|> Enum.map(fn {k,v} ->  if v == 1, do: k  end) 
|> Enum.reject( &is_nil/1)

OR

[2, 3, 4, 4, 5, 6, 6, 6, 7, 8, 8, 8, 9, 9, 10, 10, 10] 
|> Enum.frequencies 
|> Enum.filter(fn {_k,v} ->  v == 1  end) 
|> Enum.map( fn {k,_v} -> k  end)

借助此功能,您可以利用舒适的可组合管道操作器?