Pythonで複数の辞書のキーに対する集合演算(共通、和、差、対称差)

Modified: | Tags: Python, 辞書

Pythonで辞書(dict型オブジェクト)のメソッドkeys()items()を使うと、キーkeyおよびキーと値のタプル(key, value)に対して集合演算が可能。

キーと値のタプルから辞書を生成できるので、例えば、複数の辞書に共通する要素(キーと値)からなる辞書を生成したりできる。

辞書オブジェクトのkeys()メソッドとitems()メソッド

辞書オブジェクトにはkeys()メソッドとitems()メソッドがある。

keys()はキーkeyの、items()はキーと値のタプル(key, value)のビューを返す。

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

print(d1.keys())
# dict_keys(['a', 'b', 'c'])

print(type(d1.keys()))
# <class 'dict_keys'>

print(d1.items())
# dict_items([('a', 1), ('b', 2), ('c', 3)])

print(type(d1.items()))
# <class 'dict_items'>

それぞれdict_keys型、dict_items型だが、set型のような集合演算をサポートしている。

辞書オブジェクトには値valueのビューを返すvalues()メソッドもあるが、値は重複する場合があるので集合演算はサポートされていない。

以下、keys()メソッドとitems()メソッドを利用した集合演算の例を示す。

複数の辞書に共通のキーを抽出(共通部分)

複数の辞書に共通しているキーはkeys()メソッドと&演算子で抽出できる。

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

intersection_keys = d1.keys() & d2.keys()
print(intersection_keys)
# {'c', 'b'}

集合演算の結果はset型。以降の例でも同じ。

print(type(intersection_keys))
# <class 'set'>

items()メソッドの場合、キーと値が両方とも共通のものが抽出される。キーのみ、あるいは、値のみが共通のものは除外される。

intersection_items = d1.items() & d2.items()
print(intersection_items)
# {('b', 2)}

辞書オブジェクトのコンストラクタdict()にタプル(key, value)の集合(items()メソッドの集合演算結果)を渡すと辞書を生成できる。

intersection_dict = dict(d1.items() & d2.items())
print(intersection_dict)
# {'b': 2}

print(type(intersection_dict))
# <class 'dict'>

複数の辞書に含まれるキーをすべて抽出(和集合)

複数の辞書に含まれるすべてのキー、つまり、複数の辞書のいずれかに少なくとも一つ含まれるキー(和集合)は|演算子で抽出できる。

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

union_keys = d1.keys() | d2.keys()
print(union_keys)
# {'d', 'c', 'a', 'b'}

items()メソッドの場合は以下の通り。キーが共通でも値が異なる要素は別々に抽出される。

union_items = d1.items() | d2.items()
print(union_items)
# {('b', 2), ('a', 1), ('c', 4), ('d', 5), ('c', 3)}

この例のようにキーが共通で値が異なる要素があると、その集合から辞書を生成する場合にどちらか一方のみが残る。どちらの値が残るかは指定できない。

union_dict = dict(d1.items() | d2.items())
print(union_dict)
# {'b': 2, 'a': 1, 'c': 3, 'd': 5}

なお、Python 3.9以降、|演算子で2つの辞書をマージできるようになった。この処理では、共通のキーがある場合は右側の辞書の値が残る。

print(d1 | d2)
# {'a': 1, 'b': 2, 'c': 4, 'd': 5}

print(d2 | d1)
# {'b': 2, 'c': 3, 'd': 5, 'a': 1}

複数の辞書のいずれかにのみ含まれるキーを抽出(差集合、対称差集合)

複数の辞書のいずれか一方にのみ含まれるキー(対称差集合)は^演算子で抽出できる。

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

symmetric_difference_keys = d1.keys() ^ d2.keys()
print(symmetric_difference_keys)
# {'d', 'a'}

items()メソッドの場合は以下の通り。|演算子(和集合)と同様に、キーが共通でも値が異なる要素は別々に抽出される。

symmetric_difference_items = d1.items() ^ d2.items()
print(symmetric_difference_items)
# {('d', 5), ('a', 1), ('c', 3), ('c', 4)}

この例のようにキーが共通で値が異なる要素があると、その集合から辞書を生成する場合にどちらか一方のみが残る。どちらの値が残るかは指定できない。

symmetric_difference_dict = dict(d1.items() ^ d2.items())
print(symmetric_difference_dict)
# {'d': 5, 'a': 1, 'c': 4}

-演算子で差集合を取得することもできる。

difference_keys = d1.keys() - d2.keys()
print(difference_keys)
# {'a'}

difference_items = d1.items() - d2.items()
print(difference_items)
# {('a', 1), ('c', 3)}

difference_dict = dict(d1.items() - d2.items())
print(difference_dict)
# {'a': 1, 'c': 3}

関連カテゴリー

関連記事