0

I'd like to combine two nested dictionaries following these rules:

  • if value is not a dictionary, override the key in resulting dictionary
  • if value is a dictionary, compute union of the two.

Example:

dic1 = {'nest': {'foo': '42', 'same_key': 'a'}, 'same_key2': {'k1': 'v1'}}
dic2 = {'nest': {'bar': '43', 'same_key': 'b'}, 'same_key2': {'k2': 'v2'}}

dic1+dic2:

{'nest': {'foo': '42', 'bar': '43', 'same_key': 'b'}, 'same_key2': {'k1': 'v1', 'k2', 'v2'}}

This solution overrides the key and does not do the union part.

3
  • You have to define “union” somehow.
    – D. Ben Knoble
    Aug 12, 2021 at 17:19
  • 2
    have you tried the different modes of extend()? Aug 12, 2021 at 18:24
  • yes, 'force' and 'keep' just prioritize which dictionary's values will remain in the extended result. I modified the function in the linked solution and it worked for couple of tests I did. Feedback on my changes (below) is appreciated to iron out issues with it
    – listboss
    Aug 12, 2021 at 20:09

1 Answer 1

0

This is what I ended up using to achieve the example described in my question. Any improvements?

" Merge two dictionaries, also recursively combining nested keys.
" Otherwise 'override' takes priority.

function! g:MyMerge(defaults, override) abort
  let l:new = a:defaults
  for [l:k, l:v] in items(a:override)
    if type(get(l:new, l:k)) is v:t_dict && type(l:v) is v:t_dict
      call g:MyMerge(l:new[l:k], l:v)
    else
      let l:new[l:k] = l:v
    endif
  endfor
  return l:new
endfun
1
  • "Any improvements?" Just one nitpick: I think the g: is redundant and you don't need to use it here you could just create function! MyMerge... but that's a detail.
    – statox
    Aug 13, 2021 at 12:29

Not the answer you're looking for? Browse other questions tagged or ask your own question.