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 は小さいほうの集合のサイズだ。リストの包含チェックよりも高速に動作する。