我试图从列表中找到非重复值,例如
原始列表:
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中是否有更好的方法来实现这个目标
答案 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)
借助此功能,您可以利用舒适的可组合管道操作器?