Bagaimana saya bisa menggabungkan dua kamus di Vim?

9

Saya punya dua dicts:

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

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

Bagaimana saya bisa menggabungkan kunci dari overridesehingga saya berakhir dengan dict baru seperti:

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

Jawaban:

7

Anda bisa menggunakan extend():

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

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

Kunci dari argumen kedua menimpa yang ada di argumen pertama. The defaultsdict akan dimodifikasi di tempat , yang mungkin tidak ingin. Gunakan copy()untuk mencegah itu:

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

Ini terutama sesuatu yang harus berhati-hati ketika Anda mengirimkan dict ke suatu fungsi, karena itu dilewatkan oleh referensi (jadi itu akan dimodifikasi di luar fungsi juga).


Perhatikan bahwa itu tidak akan menggabungkan dicts bersarang, yang mungkin atau mungkin bukan hal yang baik, tergantung pada apa yang Anda cari:

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

Anda akan memerlukan fungsi pembantu kecil untuk menggabungkan secara acak dicts bersarang:

" 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

Anda dapat menghapus copy()jika Anda ingin memodifikasinya di tempat (sedikit lebih cepat, tetapi mungkin tidak terduga).

Martin Tournoij
sumber