Как мне объединить два словаря в Vim?

9

У меня есть два слова:

:let defaults = {'hello': 'world', 'bye': 'jupiter'}

:let override = {'hello': 'mars'}

Как я могу объединить ключи overrideтак, чтобы я получил новый dict как:

{'hello': 'mars', 'bye': 'jupiter'}
Мартин Турной
источник

Ответы:

7

Вы можете использовать extend():

:let defaults = {'hello': 'world', 'bye': 'jupiter'}
:let override = {'hello': 'mars'}

:echo extend(defaults, override)
{'hello': 'mars', 'bye': 'jupiter'}

Ключи от второго аргумента переопределяют любые существующие в первом. defaultsДИКТ будет изменен в месте , которое не может быть желанным. Используйте copy()для предотвращения этого:

:call extend(copy(defaults), override)
:echo defaults
{'hello': 'world', 'bye': 'jupiter'}

Это особенно важно, когда вы передаете dict функции, поскольку она передается по ссылке (поэтому она также будет изменена вне функции).


Обратите внимание, что это не объединит вложенные диктовки, что может или не может быть хорошей вещью, в зависимости от того, что вы ищете:

:echo extend({'nest': {'a': 'b'}}, {'nest': {'b': 'XXXX'}})
{'nest': {'b': 'XXXX'}}

Вам понадобится небольшая вспомогательная функция для рекурсивного объединения вложенных слов:

" Merge two dictionaries, also recursively merging nested keys.
"
" Use extend() if you don't need to merge nested keys.
fun! s:merge(defaults, override) abort
  let l:new = copy(a:defaults)
  for [l:k, l:v] in items(a:override)
    let l:new[l:k] = (type(l:v) is v:t_dict && type(get(l:new, l:k)) is v:t_dict)
          \ ? s:merge(l:new[l:k], l:v)
          \ : l:v
  endfor
  return l:new
endfun

Вы можете удалить его, copy()если хотите изменить его на месте (немного быстрее, но, возможно, неожиданно).

Мартин Турной
источник