比较两个平等列表的惯用方法是什么?

时间:2017-12-07 11:40:46

标签: list erlang elixir

我有两个列表需要检查它们的元素是否相等(不是浅层检查,对于我可能依赖Kernel.==/2的元素。)

目前,我有:

[l1 -- l2] ++ [l2 -- l1] == []

它看起来有点过于复杂,对我来说并不是很惯用。我错过了什么吗?是否有更好的方法来比较两个列表的相等性?

2 个答案:

答案 0 :(得分:10)

我能想到的最简单方法是对列表进行排序并进行比较:

Enum.sort(l1) == Enum.sort(l2)

对于基于O(n log n)的解决方案,这将在O(n ^ 2)时间内运行,而不是Kernel.--/2

我们不能在这里使用普通的Set数据结构,因为列表可以包含重复项,并且必须跟踪它们的计数。我们可以使用Map来计算每个元素的频率,然后比较它们:

iex(1)> l1 = ~w|a a b|a
[:a, :a, :b]
iex(2)> l2 = ~w|a b|a
[:a, :b]
iex(3)> m1 = l1 |> Enum.reduce(%{}, fn x, acc -> Map.update(acc, x, 1, & &1 + 1) end)
%{a: 2, b: 1}
iex(4)> m2 = l2 |> Enum.reduce(%{}, fn x, acc -> Map.update(acc, x, 1, & &1 + 1) end)
%{a: 1, b: 1}
iex(5)> m1 == m2
false
iex(6)> l2 = ~w|a b a|a
[:a, :b, :a]
iex(7)> m2 = l2 |> Enum.reduce(%{}, fn x, acc -> Map.update(acc, x, 1, & &1 + 1) end)
%{a: 2, b: 1}
iex(8)> m1 == m2
true

这也是O(n log n),因此您可能希望使用您需要查看哪种数据表现更好的数据来对这两种解决方案进行基准测试。

答案 1 :(得分:2)

Dogbert的解决方案很合适,但它仍然在Orcish中。

在Erlang中,这将是:

lists:sort(List1) == lists:sort(List2)

深度比较看起来几乎相同,但当然必须遍历每个列表中的结构。

要考虑的一个因素是列表的排序 的意思。字符串就是一个很好的例子,玩家排名,起始位置,游戏热键位置以及最后使用时间最长的缓存列表也是如此。所以时要记住比较的意义:"这两个列表是否包含相同数量和类型的东西?"与&#34不同;这两个列表在语义上是否相同?"

考虑比较字谜:

lists:sort("AT ERR GET VICE") == lists:sort("IT ERR ETC GAVE")

这可以作为anagram比较,但根本不作为语义比较。