Pythonで辞書をマージするにはどうすればよいですか?


90
d3 = dict(d1, **d2)

これにより辞書が統合されることを理解しています。しかし、それはユニークですか?d1がd2と同じキーを持っているが値が異なる場合はどうなりますか?d1とd2をマージしたいのですが、重複するキーがある場合はd1が優先されます。


9
このトリックは、**すべてのキーd2が文字列でない限り、キーワード引数渡しの乱用と見なされることに注意してください。のすべてのキーd2が文字列ではない場合、これはPython 3.2、およびJython、IronPython、PyPyなどのPythonの代替実装では失敗します。たとえば、mail.python.org/pipermail/python-dev/2010-April/099459.htmlを参照してください。
マークディキンソン

回答:


151

.update()オリジナルが必要なくなった場合は、このメソッドを使用できますd2

辞書を他のキーと値のペアで更新し、既存のキーを上書きします。リターンNone

例えば:

>>> d1 = {'a': 1, 'b': 2} 
>>> d2 = {'b': 1, 'c': 3}
>>> d2.update(d1)
>>> d2
{'a': 1, 'c': 3, 'b': 2}

更新:

もちろん、最初に辞書をコピーして、新しいマージ済み辞書を作成することができます。これは必要な場合と必要でない場合があります。辞書に複合オブジェクト(リストやクラスインスタンスなどの他のオブジェクトを含むオブジェクト)がある場合は、それcopy.deepcopyも考慮する必要があります。


1
この場合、競合するキーが見つかった場合、d1要素が正しく優先されます
Trey Hunner、

それでも必要な場合は、コピーを作成してください。d3 = d2.copy()d3.update(d1)しかし、d1 + d2が言語に追加されるのを確認したいのですが。
stach

4
d1 + d2は、競合時に1つの辞書を優先する必要があるため問題があり、どの辞書が特に明確ではありません。
rjh

d1 + d2は、Pythonがマルチマップを取得する場合にのみ実装されます。それ以外の場合は、ユーザーへのあいまいさが8バイトのタイピングゲインを混乱させる原因になります。
Nick Bastin

この例では、ディクショナリにオブジェクトがあります。isinstance(int, object) is Trueまだdeepcopy必要ではないようです。
アントニーハッチキンズ2013年

43

Python2では、

d1={'a':1,'b':2}
d2={'a':10,'c':3}

d1はd2をオーバーライドします。

dict(d2,**d1)
# {'a': 1, 'c': 3, 'b': 2}

d2はd1をオーバーライドします

dict(d1,**d2)
# {'a': 10, 'c': 3, 'b': 2}

この振る舞いは単なる実装ではありません。それはドキュメントで保証されています

キーが位置引数とキーワード引数の両方で指定されている場合、キーワードに関連付けられた値は辞書に保持されます。


3
Python 3.2および現在のバージョンのJython、PyPy、IronPythonでは、例が失敗し(TypeErrorが生成されます)、Pythonのこれらのバージョンでは、dictを**表記で渡す場合、そのdictのすべてのキーは文字列である必要があります。詳細については、mail.python.org / pipermail / python-dev / 2010 - April / 099427.htmlから始まるpython-devスレッドをご覧ください。
マークディキンソン

@マーク:頭を上げてくれてありがとう。CPython以外の実装と互換性を持つようにコードを編集しました。
unutbu

3
キーが文字列と数値のタプルの場合、失敗します。たとえば。d1 = {(1、 'a'):1、(1、 'b'):0、} d2 = {(1、 'a'):1、(2、 'b'):2、(2、 'a'):1、}
MySchizoBuddy 2013

解凍構文に関して、Python 3.5で予定されている変更については、この投稿を参照してください。
Ioannis Filippidis 2015

私はそれがうまくいくと言ってd = dict(**d1, **d2)いましたが、@ IoannisFilippidisが彼らのコメントで参照しているものです。おそらくここにスニペットを含めることはより明確だったので、ここにあります。
dwanderson 2017

14

d1競合を優先させたい場合は、次のようにします。

d3 = d2.copy()
d3.update(d1)

それ以外の場合は、とを逆にd2d1ます。


1

私の解決策は、マージ関数を定義することです。それは洗練されたものではなく、たった一行の費用です。Python 3のコードは次のとおりです。

from functools import reduce
from operator import or_

def merge(*dicts):
    return { k: reduce(lambda d, x: x.get(k, d), dicts, None) for k in reduce(or_, map(lambda x: x.keys(), dicts), set()) }

テスト

>>> d = {0: 0, 1: 1, 2: 4, 3: 9, 4: 16}
>>> d_letters = {0: 'a', 1: 'b', 2: 'c', 3: 'd', 4: 'e', 5: 'f', 6: 'g', 7: 'h', 8: 'i', 9: 'j', 10: 'k', 11: 'l', 12: 'm', 13: 'n', 14: 'o', 15: 'p', 16: 'q', 17: 'r', 18: 's', 19: 't', 20: 'u', 21: 'v', 22: 'w', 23: 'x', 24: 'y', 25: 'z', 26: 'A', 27: 'B', 28: 'C', 29: 'D', 30: 'E', 31: 'F', 32: 'G', 33: 'H', 34: 'I', 35: 'J', 36: 'K', 37: 'L', 38: 'M', 39: 'N', 40: 'O', 41: 'P', 42: 'Q', 43: 'R', 44: 'S', 45: 'T', 46: 'U', 47: 'V', 48: 'W', 49: 'X', 50: 'Y', 51: 'Z'}
>>> merge(d, d_letters)
{0: 'a', 1: 'b', 2: 'c', 3: 'd', 4: 'e', 5: 'f', 6: 'g', 7: 'h', 8: 'i', 9: 'j', 10: 'k', 11: 'l', 12: 'm', 13: 'n', 14: 'o', 15: 'p', 16: 'q', 17: 'r', 18: 's', 19: 't', 20: 'u', 21: 'v', 22: 'w', 23: 'x', 24: 'y', 25: 'z', 26: 'A', 27: 'B', 28: 'C', 29: 'D', 30: 'E', 31: 'F', 32: 'G', 33: 'H', 34: 'I', 35: 'J', 36: 'K', 37: 'L', 38: 'M', 39: 'N', 40: 'O', 41: 'P', 42: 'Q', 43: 'R', 44: 'S', 45: 'T', 46: 'U', 47: 'V', 48: 'W', 49: 'X', 50: 'Y', 51: 'Z'}
>>> merge(d_letters, d)
{0: 0, 1: 1, 2: 4, 3: 9, 4: 16, 5: 'f', 6: 'g', 7: 'h', 8: 'i', 9: 'j', 10: 'k', 11: 'l', 12: 'm', 13: 'n', 14: 'o', 15: 'p', 16: 'q', 17: 'r', 18: 's', 19: 't', 20: 'u', 21: 'v', 22: 'w', 23: 'x', 24: 'y', 25: 'z', 26: 'A', 27: 'B', 28: 'C', 29: 'D', 30: 'E', 31: 'F', 32: 'G', 33: 'H', 34: 'I', 35: 'J', 36: 'K', 37: 'L', 38: 'M', 39: 'N', 40: 'O', 41: 'P', 42: 'Q', 43: 'R', 44: 'S', 45: 'T', 46: 'U', 47: 'V', 48: 'W', 49: 'X', 50: 'Y', 51: 'Z'}
>>> merge(d)
{0: 0, 1: 1, 2: 4, 3: 9, 4: 16}
>>> merge(d_letters)
{0: 'a', 1: 'b', 2: 'c', 3: 'd', 4: 'e', 5: 'f', 6: 'g', 7: 'h', 8: 'i', 9: 'j', 10: 'k', 11: 'l', 12: 'm', 13: 'n', 14: 'o', 15: 'p', 16: 'q', 17: 'r', 18: 's', 19: 't', 20: 'u', 21: 'v', 22: 'w', 23: 'x', 24: 'y', 25: 'z', 26: 'A', 27: 'B', 28: 'C', 29: 'D', 30: 'E', 31: 'F', 32: 'G', 33: 'H', 34: 'I', 35: 'J', 36: 'K', 37: 'L', 38: 'M', 39: 'N', 40: 'O', 41: 'P', 42: 'Q', 43: 'R', 44: 'S', 45: 'T', 46: 'U', 47: 'V', 48: 'W', 49: 'X', 50: 'Y', 51: 'Z'}
>>> merge()
{}

任意の数の辞書引数に対して機能します。これらのディクショナリに重複するキーがある場合、引数リストの右端のディクショナリのキーが優先されます。


1
.update呼び出しがmerged={}続く単純なループ(後にが続くfor d in dict: merged.update(d))は、短く、読みやすく、効率的です。
Mark Dickinson

1
または本当にs を使用reduceしたい場合lambdaはどうreturn reduce(lambda x, y: x.update(y) or x, dicts, {})ですか?
Mark Dickinson

1
シェルでコードを試して、それが正しいかどうかを確認できます。私がやろうとしていたことは、同じ機能でさまざまな数の辞書引数を取ることができる関数を書くことです。x.update(y)は常にNoneを返すため、ラムダでx.update(y)を使用しないことをお勧めします。そして、さまざまな数の辞書引数を取り、提供された関数で重複キーを処理する、より一般的な関数merge_withを記述しようとしています。完了したら、ソリューションの関連性が高い別のスレッドに投稿します。
Lei Zhao

ここだリンク私はもっと一般的な解決策を書きました。ようこそ、ご覧ください。
Lei Zhao、


1

からPython 3.9、演算子|は2つの辞書からのキーと値をマージして新しい辞書を作成します。

# d1 = { 'a': 1, 'b': 2 }
# d2 = { 'b': 1, 'c': 3 }
d3 = d2 | d1
# d3: {'b': 2, 'c': 3, 'a': 1}

この:

マージされたキーとd2およびd1の値を使用して、新しいディクショナリd3を作成します。d2とd1がキーを共有する場合、d1の値が優先されます。


また|=、d1値を優先して、d1をマージしてd2を変更する演算子にも注意してください。

# d1 = { 'a': 1, 'b': 2 }
# d2 = { 'b': 1, 'c': 3 }
d2 |= d1
# d2: {'b': 2, 'c': 3, 'a': 1}


0

上記のとおり、使用するのd2.update(d1)が最善の方法であり、d2必要な場合は最初にコピーすることもできると思います。

ただし、dict(d1, **d2)キーワード引数は文字列である必要があるため、一般的に辞書をマージするには実際に悪い方法であることを指摘しておきます。したがって、次のような場合は失敗しますdict

{
  1: 'foo',
  2: 'bar'
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.