I have a very deep map of maps with lots of values, where I want to update only a few values, while keeping all the rest. I thought that maps:merge/2
would be just the ticket, but the problem with that is that it will replace every key, all the way up to the root. I only want to update the value in the leaf. This is what maps:merge/2
does:
>maps:merge(#{a => apple, b => #{c => cherry, d => date}}, #{b => #{c => cantaloupe}}).
#{a => apple, b => #{c => cantaloupe}}).
The result I would like is #{a => apple, b => #{c => cantaloupe, d => date}}
. I tried working with maps:merge_with/3
, but couldn't figure it out. Is there a clever way to do this?
Using maps:merge_with/3
with a recursive function should be enough here.
A quick and dirty one-liner:
1> Fun = fun F(_K, L, R) when is_map(L) -> maps:merge_with(F, L, R); F(_K, _L, R) -> R end.
#Fun<erl_eval.17.39164016>
2> Fun(nil, #{a => apple, b => #{c => cherry, d => date}}, #{b => #{c => cantaloupe}}).
#{b => #{c => cantaloupe,d => date},a => apple}
A more readable version:
deep_merge(Left, Right) -> maps:merge_with(fun
(_, L, R) when is_map(L) -> deep_merge(L, R);
(_, _, R) -> R end
, Left, Right).