Правильный способ объединить вложенную карту, которая может не существовать - PullRequest
0 голосов
/ 05 мая 2018

Учитывая два возможных входа: 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 голосов
/ 05 мая 2018

Вы можете использовать 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}}
0 голосов
/ 05 мая 2018

Я думаю, вы ищете функцию 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}}.

...