Comment fusionner deux dictionnaires dans Vim?

9

J'ai deux dict:

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

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

Comment puis-je fusionner les clés overridepour que je me retrouve avec un nouveau dict comme ceci:

{'hello': 'mars', 'bye': 'jupiter'}
Martin Tournoij
la source

Réponses:

7

Vous pouvez utiliser extend():

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

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

Les clés du deuxième argument remplacent celles existantes dans le premier. Le defaultsdict sera modifié en place , ce qui peut ne pas être souhaité. Utilisez copy()pour éviter cela:

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

C'est particulièrement quelque chose à faire attention lorsque vous passez un dict à une fonction, car il est passé par référence (il sera donc également modifié en dehors de la fonction).


Notez qu'il ne fusionnera pas les dict imbriqués, ce qui peut ou non être une bonne chose, selon ce que vous recherchez:

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

Vous aurez besoin d'une petite fonction d'aide pour fusionner récursivement les dictés imbriqués:

" 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

Vous pouvez supprimer le copy()si vous souhaitez le modifier sur place (un peu plus vite, mais peut-être inattendu).

Martin Tournoij
la source