Jak mogę połączyć dwa słowniki w Vimie?

9

Mam dwa dyktanda:

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

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

Jak mogę scalić klucze, overrideaby uzyskać nowy dyktando:

{'hello': 'mars', 'bye': 'jupiter'}
Martin Tournoij
źródło

Odpowiedzi:

7

Możesz użyć extend():

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

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

Klucze z drugiego argumentu zastępują wszystkie istniejące w pierwszym. defaultsDICT zostaną zmodyfikowane w miejscu , które nie mogą być potrzebne. Użyj, copy()aby zapobiec:

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

Jest to szczególnie ważne, na co należy uważać, gdy przekazujesz dykt do funkcji, ponieważ jest ona przekazywana przez referencję (więc zostanie zmodyfikowana również poza funkcją).


Pamiętaj, że nie scali zagnieżdżonych nagrań, co może, ale nie musi być dobrą rzeczą, w zależności od tego, czego szukasz:

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

Potrzebujesz małej funkcji pomocniczej, aby rekurencyjnie łączyć zagnieżdżone dyktaty:

" 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

Możesz usunąć, copy()jeśli chcesz go zmodyfikować w miejscu (nieco szybciej, ale być może nieoczekiwanie).

Martin Tournoij
źródło