¿Cómo puedo fusionar dos diccionarios en Vim?

9

Tengo dos dictados:

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

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

¿Cómo puedo fusionar las claves overridepara que termine con un nuevo dict así:

{'hello': 'mars', 'bye': 'jupiter'}
Martin Tournoij
fuente

Respuestas:

7

Puedes usar extend():

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

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

Las claves del segundo argumento anulan las existentes en el primero. El defaultsdict se modificará en su lugar , lo que puede no ser deseado. Use copy()para prevenir eso:

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

Esto es especialmente algo de lo que debes tener cuidado cuando pasas un dict a una función, ya que se pasa por referencia (por lo que también se modificará fuera de la función).


Tenga en cuenta que no fusionará los dictados anidados, lo que puede o no ser bueno, dependiendo de lo que esté buscando:

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

Necesitará una pequeña función auxiliar para fusionar recursivamente los dictados anidados:

" 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

Puede eliminar el copy()si desea modificarlo en el lugar (un poco más rápido, pero posiblemente inesperado).

Martin Tournoij
fuente