2015/08/25

Python Tips:複数の辞書を統合してひとつにしたい

Python でふたつ以上の辞書をひとつにまとめる方法をご紹介します。「ふたつにまとめる」というときに、重複するキーがあった場合の挙動によっていくつかのパターンに分けることができます。

ひとつめの辞書を優先する
ふたつめの辞書で上書きする
何らかの方法でまとめる

以下順番にやり方を見ていきましょう。

ひとつめの辞書を優先する


まずはひとつめの「ひとつめの辞書を優先する」方法から。これは単純に重複チェックをする形になりそうです。

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

def merge_dict1(d1, d2):
    d_merged = d1.copy()
    for k, v in d2.items():
        if not k in d_merged:
            d_merged[k] = v
    return d_merged

d3 = merge_dict1(d1, d2)
print(d3)
# => {'c': 3, 'b': 4, 'a': 3}

ふたつめの辞書で上書きする


つづいてふたつめの「ふたつめの辞書で上書きする」方法。こちらには dict 型の update メソッドが便利です。

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

def merge_dict2(d1, d2):
    d_merged = d1.copy()
    d_merged.update(d2)
    return d_merged

d3 = merge_dict2(d1, d2)
print(d3)
# => {'c': 3, 'b': 2, 'a': 1}

何らかの方法でまとめる


最後に、どちらかの要素だけを使うのではなく両方の要素を何らかの方法でまとめる方法を見てみます。たとえば、同じ要素が存在する場合はそれらの合計値を取る場合は次のようにします。

from operator import add

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

def merge_dict3(func, d1, d2):
    d_merged = d1.copy()
    for k, v in d2.items():
        if k in d_merged:
            d_merged[k] = func(d_merged[k], v)
        else:
            d_merged[k] = v
    return d_merged

d3 = merge_dict3(add, d1, d2)
print(d3)
# => {'c': 3, 'b': 6, 'a': 4}

ここで func や operator.add を使う必要性はありませんが、この関数定義にしておくことで汎用性を持たせることができます。たとえば merge_dict3 は次のように使いまわせます。

d4 = merge_dict3(lambda a, b: a + b, d1, d2)
print(d4)
# => {'c': 3, 'b': 6, 'a': 4}

d5 = merge_dict3(lambda a, b: a * b, d1, d2)
print(d5)
# => {'a': 3, 'b': 8, 'c': 3}

別のアプローチとして、加算の場合には collections.Counter クラスを経由してシンプルに記述することもできます。

from collections import Counter

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

def merge_dict4(d1, d2):
    c1 = Counter(d1)
    c2 = Counter(d2)
    return dict(c1 + c2)

d3 = merge_dict4(d1, d2)
print(d3)
# => {'b': 6, 'a': 4, 'c': 3}

参考
python - Is there any pythonic way to combine two dicts (adding values for keys that appear in both)? - Stack Overflow

0 件のコメント: