合并可能不存在的嵌套映射的正确方法

时间:2018-05-05 09:40:25

标签: elixir

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

OR 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 个答案:

答案 0 :(得分:1)

我认为您正在寻找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}}

答案 1 :(得分:1)

您可以使用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}}