Elixir从两个列表中删除常用元素

jah*_*n07 2 elixir

我想从列表a中删除列表b中的元素.列表a在执行此代码后打印[1,2,3,4].

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()
Run Code Online (Sandbox Code Playgroud)

Mik*_*hot 10

您也可以使用--运算符(https://hexdocs.pm/elixir/Kernel.html#--/2)

iex> [1, 2, 3] -- [1, 2]
[3]
Run Code Online (Sandbox Code Playgroud)


den*_*lin 9

目前(Enum.filter--)在其他答案中呈现的两种方式都适用于小型列表.但是,列表很大,效率很低.

如果列表很大,最好使用MapSet:

MapSet.difference(MapSet.new(a), MapSet.new(b)) |> MapSet.to_list
Run Code Online (Sandbox Code Playgroud)

它花了一些时间将两个列表转换为MapSet,然后将结果转换回列表,但这些操作是n log(n),而这里的Enum.filtersubstraction(--)是二次的.

我准备了一个基准测试要点.

总结:对于非常短的列表减法是最快的,对于大约100个元素长的列表Enum.filter是最快的,并且对于列表大约1000个元素MapSet.difference是最快的.在具有100K元素的列表上,它快了几百倍.

实际上,在列表上,此大小的MapSet.difference工作时间为0.08秒,Enum.filter16秒和减法44秒.

更新:Dogbert让我也对Erlang进行基准测试ordsets:

:ordsets.subtract(:ordsets.from_list(a), :ordsets.from_list(b)) |> :ordsets.to_list
Run Code Online (Sandbox Code Playgroud)

它的工作速度比MapSet,特别是在中型列表上长约1000条记录(MapSet大约1.4慢一点).

  • 让大家大吃一惊!我在 Elixir 1.12.1/OTP24 上重新运行了基准测试,性能特征发生了显着变化:https://gist.github.com/iStefo/d83bc2737168daf6faf7fa0d2fea2ce2 现在,列表减法(`--`)始终是最快的(或同等),无论列表长度如何!这与 erlang 效率指南中的“退休神话”部分一致:http://erlang.org/doc/efficiency_guide/retired_myths.html#myth--list-subtraction-----operator--is -慢的 (3认同)