Pythonのset型で集合演算をマスター【和集合・積集合・部分集合完全ガイド】

 

Pythonのset型は、数学の集合論を直感的にプログラムで扱える優れたデータ型です。この記事では、和集合、積集合、部分集合の判定など、set型の全機能を実践的なサンプルコードと共に詳しく解説します。

set型の基本

セットの作成方法

# 基本的な作成方法
set1 = {1, 2, 3, 4, 5}
set2 = set([1, 2, 3, 4, 5])  # リストから作成
set3 = set("hello")          # 文字列から作成 {'h', 'e', 'l', 'o'}

print(set1)  # {1, 2, 3, 4, 5}
print(set3)  # {'h', 'e', 'l', 'o'}

空のセットと重複の除去

# 空のセット
empty_set = set()           # 空のセット
# empty_set = {}            # これは辞書!

# 重複要素の自動除去
duplicate_list = [1, 2, 2, 3, 3, 3, 4]
unique_set = set(duplicate_list)
print(unique_set)  # {1, 2, 3, 4}

基本的なセット操作

要素の追加と削除

fruits = {"apple", "banana", "orange"}

# 要素の追加
fruits.add("grape")
print(fruits)  # {'apple', 'banana', 'orange', 'grape'}

# 複数要素の追加
fruits.update(["mango", "kiwi"])
print(fruits)

# 要素の削除
fruits.remove("banana")     # エラーが出る可能性あり
fruits.discard("cherry")    # エラーが出ない
popped = fruits.pop()       # ランダムに削除

セットの長さと存在確認

numbers = {1, 3, 5, 7, 9}

# セットのサイズ
size = len(numbers)         # 5
print(f"要素数: {size}")

# 要素の存在確認
print(3 in numbers)         # True
print(4 in numbers)         # False
print(6 not in numbers)     # True

和集合(Union)

union()メソッドと|演算子

set_a = {1, 2, 3}
set_b = {3, 4, 5}

# union()メソッド
union1 = set_a.union(set_b)
print(union1)  # {1, 2, 3, 4, 5}

# |演算子
union2 = set_a | set_b
print(union2)  # {1, 2, 3, 4, 5}

# 複数セットの和集合
set_c = {5, 6, 7}
union3 = set_a | set_b | set_c
print(union3)  # {1, 2, 3, 4, 5, 6, 7}

update()による和集合の代入

set_a = {1, 2, 3}
set_b = {3, 4, 5}

# 元のセットを変更
set_a.update(set_b)  # set_a |= set_b と同等
print(set_a)         # {1, 2, 3, 4, 5}

積集合(Intersection)

intersection()メソッドと&演算子

set_a = {1, 2, 3, 4}
set_b = {3, 4, 5, 6}

# intersection()メソッド
intersection1 = set_a.intersection(set_b)
print(intersection1)  # {3, 4}

# &演算子
intersection2 = set_a & set_b
print(intersection2)  # {3, 4}

# 複数セットの積集合
set_c = {2, 3, 4, 7}
intersection3 = set_a & set_b & set_c
print(intersection3)  # {3, 4}

共通要素の存在確認

set_a = {1, 2, 3}
set_b = {4, 5, 6}
set_c = {2, 4, 6}

# 共通要素があるかチェック
print(set_a.isdisjoint(set_b))  # True(共通要素なし)
print(set_a.isdisjoint(set_c))  # False(共通要素あり)

差集合(Difference)

difference()メソッドと-演算子

set_a = {1, 2, 3, 4, 5}
set_b = {3, 4, 5, 6, 7}

# difference()メソッド
diff1 = set_a.difference(set_b)
print(diff1)  # {1, 2}

# -演算子
diff2 = set_a - set_b
print(diff2)  # {1, 2}

# 逆方向の差集合
diff3 = set_b - set_a
print(diff3)  # {6, 7}

差集合の代入

set_a = {1, 2, 3, 4, 5}
set_b = {3, 4, 5}

# 元のセットから要素を除去
set_a.difference_update(set_b)  # set_a -= set_b と同等
print(set_a)  # {1, 2}

対称差集合(Symmetric Difference)

symmetric_difference()メソッドと^演算子

set_a = {1, 2, 3, 4}
set_b = {3, 4, 5, 6}

# symmetric_difference()メソッド
sym_diff1 = set_a.symmetric_difference(set_b)
print(sym_diff1)  # {1, 2, 5, 6}

# ^演算子
sym_diff2 = set_a ^ set_b
print(sym_diff2)  # {1, 2, 5, 6}

# 対称差集合は (A-B) ∪ (B-A) と同じ
manual_sym_diff = (set_a - set_b) | (set_b - set_a)
print(manual_sym_diff)  # {1, 2, 5, 6}

部分集合・上位集合の判定

subset(部分集合)の判定

set_a = {1, 2, 3}
set_b = {1, 2, 3, 4, 5}
set_c = {1, 2, 3}

# 部分集合の判定
print(set_a.issubset(set_b))    # True(AはBの部分集合)
print(set_a <= set_b)           # True(同上)

# 真部分集合の判定
print(set_a < set_b)            # True(AはBの真部分集合)
print(set_a < set_c)            # False(同じセット)

superset(上位集合)の判定

set_a = {1, 2, 3, 4, 5}
set_b = {2, 3}

# 上位集合の判定
print(set_a.issuperset(set_b))  # True(AはBの上位集合)
print(set_a >= set_b)           # True(同上)

# 真上位集合の判定
print(set_a > set_b)            # True(AはBの真上位集合)

frozenset(不変セット)

frozensetの基本

# 不変セットの作成
frozen_set = frozenset([1, 2, 3, 4])
print(frozen_set)  # frozenset({1, 2, 3, 4})

# セットの要素としてfrozensetを使用
set_of_sets = {
    frozenset([1, 2]),
    frozenset([3, 4]),
    frozenset([1, 2])  # 重複は除去される
}
print(set_of_sets)

frozensetと通常setの演算

normal_set = {1, 2, 3}
frozen_set = frozenset([2, 3, 4])

# 演算結果は通常set
union = normal_set | frozen_set
print(type(union))  # <class 'set'>
print(union)        # {1, 2, 3, 4}

実践的な応用例

重複データの検出

def find_duplicates(data_list):
    seen = set()
    duplicates = set()
    
    for item in data_list:
        if item in seen:
            duplicates.add(item)
        else:
            seen.add(item)
    
    return duplicates

data = [1, 2, 3, 2, 4, 5, 3, 6]
dups = find_duplicates(data)
print(f"重複要素: {dups}")  # {2, 3}

ユーザー権限の管理

class UserPermissions:
    def __init__(self, user_id):
        self.user_id = user_id
        self.permissions = set()
    
    def grant_permission(self, permission):
        self.permissions.add(permission)
    
    def revoke_permission(self, permission):
        self.permissions.discard(permission)
    
    def has_permission(self, permission):
        return permission in self.permissions
    
    def has_all_permissions(self, required_permissions):
        return required_permissions.issubset(self.permissions)

# 使用例
user = UserPermissions("user001")
user.grant_permission("read")
user.grant_permission("write")

required = {"read", "write", "admin"}
print(user.has_all_permissions(required))  # False

データベースの差分検出

def database_diff(old_records, new_records):
    old_set = set(old_records)
    new_set = set(new_records)
    
    added = new_set - old_set
    deleted = old_set - new_set
    common = old_set & new_set
    
    return {
        'added': added,
        'deleted': deleted,
        'unchanged': common
    }

old_data = ['user1', 'user2', 'user3']
new_data = ['user2', 'user3', 'user4', 'user5']

diff = database_diff(old_data, new_data)
print(f"追加: {diff['added']}")      # {'user4', 'user5'}
print(f"削除: {diff['deleted']}")    # {'user1'}
print(f"変更なし: {diff['unchanged']}")  # {'user2', 'user3'}

性能特性と注意点

セットの検索速度

import time

# リストでの検索(O(n))
large_list = list(range(10000))
start = time.time()
result = 9999 in large_list
end = time.time()
print(f"リスト検索時間: {end-start:.6f}秒")

# セットでの検索(O(1))
large_set = set(range(10000))
start = time.time()
result = 9999 in large_set
end = time.time()
print(f"セット検索時間: {end-start:.6f}秒")

ハッシュ可能な要素のみ

# ハッシュ可能な要素
valid_set = {1, "text", (1, 2), frozenset([3, 4])}

# ハッシュ不可能な要素(エラーになる)
try:
    invalid_set = {[1, 2, 3]}  # リストは不可
except TypeError as e:
    print(f"エラー: {e}")

try:
    invalid_set = {{1, 2, 3}}  # セットは不可
except TypeError as e:
    print(f"エラー: {e}")

まとめ

Pythonのset型は以下の特徴を持つ優れたデータ型です:

  • 重複を自動的に除去
  • 高速な要素検索(O(1))
  • 直感的な集合演算
  • 数学的な集合論の完全実装

データの重複除去、集合演算、高速検索が必要な場面では、set型を積極的に活用しましょう。特にデータ分析、権限管理、差分検出などの実用的な場面で威力を発揮します。

■プロンプトだけでオリジナルアプリを開発・公開してみた!!

■AI時代の第一歩!「AI駆動開発コース」はじめました!

テックジム東京本校で先行開始。

■テックジム東京本校

「武田塾」のプログラミング版といえば「テックジム」。
講義動画なし、教科書なし。「進捗管理とコーチング」で効率学習。
より早く、より安く、しかも対面型のプログラミングスクールです。

<短期講習>5日で5万円の「Pythonミニキャンプ」開催中。

<月1開催>放送作家による映像ディレクター養成講座

<オンライン無料>ゼロから始めるPython爆速講座