代码之家  ›  专栏  ›  技术社区  ›  intentionally-left-nil

合并可能不存在的嵌套贴图的正确方法

  •  0
  • intentionally-left-nil  · 技术社区  · 6 年前

    给出两种可能的输入: a = %{ inner: %{hello: :world}}

    a = %{}

    我想合并 b = %{foo: :bar} 要生成的地图:

    %{inner: %{foo: :bar}} 在第一种情况下,或

    %{inner: %{hello: :world, foo: :bar}} 在第二个。

    我可以用

    merged = Map.get(a, :inner, %{})
    |> Map.merge(b)
    put_in(a, [:inner], merged)
    

    但有更好的内在方式吗?我认为深度合并应该比这更容易。

    2 回复  |  直到 6 年前
        1
  •  1
  •   Dogbert    6 年前

    您可以使用 update_in/3 + Access.key/2 :

    iex(1)> a1 = %{ inner: %{hello: :world}}
    %{inner: %{hello: :world}}
    iex(2)> a2 = %{}
    %{}
    iex(3)> b = %{foo: :bar}
    %{foo: :bar}
    iex(4)> update_in(a1, [Access.key(:inner, %{})], &Map.merge(&1, b))
    %{inner: %{foo: :bar, hello: :world}}
    iex(5)> update_in(a2, [Access.key(:inner, %{})], &Map.merge(&1, b))
    %{inner: %{foo: :bar}}
    
        2
  •  1
  •   Igor Drozdov    6 年前

    我想你在找 Map.merge/3 作用第三个参数是解决冲突的函数:

    a = %{inner: %{hello: :world}}
    b = %{foo: :bar}
    Map.merge(a, %{inner: b}, fn _, m1, m2 -> Map.merge(m1, m2) end)
    

    因此,在这种情况下,当发生冲突时(正在合并的两个映射具有相同的键),将调用提供的函数。什么时候 a %{} ,没有发生冲突,并且 %{inner: %{foo: :bar}} 已返回。