Elixir从两个列表中删除公共元素
问题描述:
我想从列表a中删除列表b中找到的元素。 执行此代码后,列表a正在打印[1,2,3,4]。Elixir从两个列表中删除公共元素
defmodule Test do
def listing do
a = [1,2,3,4]
b = [3,4,5,6]
Enum.each b, fn elemB ->
a = Enum.filter(a, fn(x) -> x != elemB == true end)
#IO.inspect a
end
IO.inspect a
end
end
Test.listing()
答
你并不需要一个外部Enum.each
,你可以用一个过滤器通过枚举了a
和检查每个元素,看看它是否是b
成员做到这一点:
Enum.filter(a, fn el -> !Enum.member?(b, el) end)
输出:
[1, 2]
它看起来像当前的解决方案,你试图修改a
但不会工作,因为药剂是功能性的,功能不能有副作用; each
中的a
与原始列表中的a
不一样。
答
的时刻(Enum.filter
和--
)将在小名单的工作以及在其他的答案提出的两种方式。但是,清单很大,效率很低。
如果名单是大,最好使用MapSet
:
MapSet.difference(MapSet.new(a), MapSet.new(b)) |> MapSet.to_list
它花费一些时间来两个列表转换为地图集,然后结果转换回列表,但是这些操作都是n log(n)
,而Enum.filter
和这里的减法(--
)是二次的。我准备了gist with benchmarks。
摘要:对于非常短的列表减法是最快的,对于大约100个元素长的列表Enum.filter
是最快的,对于列表大约1000个元素MapSet.difference
是最快的。在具有100K元素的列表上,它的速度要快上百倍。
其实在列表上这个大小MapSet.difference
工作0.08秒,Enum.filter
16秒,减去44秒。
UPDATE:Dogbert
问我还基准Erlang的ordsets
:
:ordsets.subtract(:ordsets.from_list(a), :ordsets.from_list(b)) |> :ordsets.to_list
它比MapSet
快,特别是在中型列出大约1000条记录长(MapSet
慢约1.4
倍)。
答
按照与@Tyler答案,
您可以用Enum.reject
,而不是Enum.filter
你的代码更清晰:
Enum.reject(a, fn el -> Enum.member?(b, el) end)
这将给予同样的结果:
Enum.filter(a, fn el -> !Enum.member?(b, el) end)
难道你还可以添加' ordsets'到基准? Erlang文档建议使用它而不是'--'。 ':ordsets.subtract(:ordsets.from_list(a),:ordsets.from_list(b))|>:ordsets.to_list'。 – Dogbert
另外,List to MapSet转换不是线性的,而是O(n log n),因为在Erlang中的Map中插入值是O(log n)。 – Dogbert
@Dogbert,我做到了,请检查结果。 –