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 '21 at 17:19
  • 2
    have you tried the different modes of extend()? Aug 12 '21 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 '21 at 20:09
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 '21 at 12:29

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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