Python の集合(部分集合と上位集合の判定)
集合の包含関係を調べることで、ある集合が別の集合に含まれるかどうかを判定できる。Python では比較演算子とメソッドの両方で判定が可能だ。
部分集合(Subset)
集合 A のすべての要素が集合 B にも含まれるとき、A は B の部分集合であるという。<= 演算子または issubset() メソッドで判定する。
a = {1, 2}
b = {1, 2, 3, 4}
print(a <= b) # True
print(a.issubset(b)) # True
自分自身との比較も True になる。数学的に、すべての集合は自分自身の部分集合だ。
a = {1, 2, 3}
print(a <= a) # True
真部分集合(Proper Subset)
真部分集合は、部分集合かつ等しくないという条件を満たす。< 演算子で判定する。
a = {1, 2}
b = {1, 2, 3}
c = {1, 2}
print(a < b) # True(a は b の真部分集合)
print(a < c) # False(a と c は等しい)
すべての要素が相手に含まれる(等しい場合も True)
すべての要素が相手に含まれ、かつ相手には追加要素がある
上位集合(Superset)
上位集合は部分集合の逆の関係だ。集合 A が集合 B のすべての要素を含むとき、A は B の上位集合(または包含集合)であるという。>= 演算子または issuperset() メソッドで判定する。
a = {1, 2, 3, 4}
b = {1, 2}
print(a >= b) # True
print(a.issuperset(b)) # True
部分集合と上位集合は対称の関係になる。
a = {1, 2}
b = {1, 2, 3, 4}
print(a <= b) # True(a は b の部分集合)
print(b >= a) # True(b は a の上位集合)
真上位集合(Proper Superset)
真上位集合は、上位集合かつ等しくないという条件だ。> 演算子で判定する。
a = {1, 2, 3, 4}
b = {1, 2}
c = {1, 2, 3, 4}
print(a > b) # True(a は b の真上位集合)
print(a > c) # False(a と c は等しい)
等価判定
2 つの集合が同じ要素を持つかどうかは == で判定する。要素の順序は関係ない。
a = {1, 2, 3}
b = {3, 2, 1}
c = {1, 2}
print(a == b) # True
print(a == c) # False
!= で不等価も判定できる。
a = {1, 2, 3}
b = {1, 2}
print(a != b) # True
互いに素(Disjoint)
2 つの集合に共通要素がないかどうかは isdisjoint() メソッドで判定する。
a = {1, 2, 3}
b = {4, 5, 6}
c = {3, 4, 5}
print(a.isdisjoint(b)) # True(共通要素なし)
print(a.isdisjoint(c)) # False(3 が共通)
isdisjoint() は積集合が空かどうかを調べるのと同じ意味だ。
a = {1, 2, 3}
b = {4, 5, 6}
print(a.isdisjoint(b)) # True
print(len(a & b) == 0) # True
ただし isdisjoint() のほうが効率的だ。積集合を実際に作成せず、共通要素が見つかった時点で False を返すため。
メソッドはイテラブルを受け取れる
演算子は集合同士でしか使えないが、issubset()、issuperset()、isdisjoint() はイテラブルを引数に取れる。
a = {1, 2}
# リストと比較
print(a.issubset([1, 2, 3, 4])) # True
# タプルと比較
print(a.issuperset((1,))) # True
# 文字列と比較
chars = {'a', 'b'}
print(chars.issubset("abc")) # True
実践的な活用例
権限チェックは部分集合判定の典型的なユースケースだ。
required_permissions = {"read", "write"}
user_permissions = {"read", "write", "delete", "admin"}
# ユーザーが必要な権限をすべて持っているか
if required_permissions <= user_permissions:
print("アクセス許可")
else:
print("権限不足")
商品のタグ検索も同様のパターンで実装できる。
product_tags = {"electronics", "smartphone", "5g", "android"}
search_tags = {"smartphone", "5g"}
# 検索タグがすべて商品タグに含まれるか
if search_tags <= product_tags:
print("マッチ")
部分集合判定は O(n) の計算量で、n は小さいほうの集合のサイズだ。リストの包含チェックよりも高速に動作する。