集合の基本:重複のないデータの集まり#

はじめに#

これまでに、リスト、タプル、辞書というPythonの重要なデータ構造について学んできました。今回は、もう一つの便利なデータ構造「集合(セット)」について学びます。集合は数学の「集合」と同じ概念で、重複のない要素の集まりを表します。

集合とは何か#

集合(セット)とは、次のような特徴を持つデータ構造です。

  1. 重複する要素を持ちません(同じ値は1つしか保存されません)
  2. 順序が保証されません(要素の順序は意味を持ちません)
  3. 変更可能です(要素の追加や削除ができます)

集合は、特に「重複を排除したいとき」や「複数のデータの共通部分や差を見つけたいとき」に役立ちます。

集合の作り方#

集合は波括弧 {} を使って作ります。これは辞書と似ていますが、キーと値のペアではなく、要素だけを並べます。また、set() 関数を使って他のデータ型から集合を作ることもできます。

>
# 波括弧を使った集合の作成
fruits = {"りんご", "バナナ", "オレンジ", "りんご"}  # 重複は自動的に削除される
print(fruits)
print(type(fruits))

# 空の集合の作成(注意:{}だけだと辞書になるので、set()を使う)
empty_set = set()
print(empty_set)
print(type(empty_set))

# リストから集合を作成
numbers_list = [1, 2, 3, 2, 1, 4, 5, 3]
numbers_set = set(numbers_list)  # 重複が削除される
print("元のリスト:", numbers_list)
print("集合にした結果:", numbers_set)
{'オレンジ', 'りんご', 'バナナ'}
<class 'set'>
set()
<class 'set'>
元のリスト: [1, 2, 3, 2, 1, 4, 5, 3]
集合にした結果: {1, 2, 3, 4, 5}

上の例からわかるように、集合を作ると重複する要素が自動的に削除されます。また、出力結果を見ると、元の入力順序とは異なる順序で表示されていることがわかります。Pythonの集合は順序を保持しないため、要素は順不同に格納されます。

なお、空の集合を作りたい場合は {} だと辞書と区別がつかないので、set() 関数を使います。

集合の基本操作#

要素の追加#

集合に要素を追加するには add() メソッドを使います。

>
# 集合の作成
colors = {"赤", "青", "緑"}
print("元の集合:", colors)

# 要素の追加
colors.add("黄")
print("要素追加後:", colors)

# 既に存在する要素を追加しても何も起こらない
colors.add("赤")
print("既存の要素を追加しても変わらない:", colors)
元の集合: {'青', '緑', '赤'}
要素追加後: {'青', '黄', '緑', '赤'}
既存の要素を追加しても変わらない: {'青', '黄', '緑', '赤'}

要素の削除#

集合から要素を削除するには、いくつかの方法があります。

>
# 集合の作成
colors = {"赤", "青", "緑", "黄", "紫"}
print("元の集合:", colors)

# remove() メソッドで要素を削除(存在しない要素はエラー)
colors.remove("紫")
print("「紫」を削除:", colors)

# discard() メソッドで要素を削除(存在しない要素でもエラーにならない)
colors.discard("黄")
print("「黄」を削除:", colors)
colors.discard("オレンジ")  # 存在しない要素でもエラーにならない
print("存在しない「オレンジ」を削除しても:", colors)

# pop() メソッドで任意の要素を取り出して削除(順序は保証されない)
removed_color = colors.pop()
print(f"popで削除した色: {removed_color}")
print("pop後の集合:", colors)

# clear() メソッドですべての要素を削除
colors.clear()
print("すべての要素を削除:", colors)
元の集合: {'黄', '赤', '紫', '緑', '青'}
「紫」を削除: {'黄', '赤', '緑', '青'}
「黄」を削除: {'赤', '緑', '青'}
存在しない「オレンジ」を削除しても: {'赤', '緑', '青'}
popで削除した色: 赤
pop後の集合: {'緑', '青'}
すべての要素を削除: set()

要素の存在確認#

集合に要素が存在するかどうかを確認するには、in 演算子を使います(リストやタプルと同様です)。

>
# 集合の作成
fruits = {"りんご", "バナナ", "オレンジ"}

# 要素の存在確認
print("「りんご」は集合に含まれる?", "りんご" in fruits)  # True
print("「メロン」は集合に含まれる?", "メロン" in fruits)  # False

# 条件分岐と組み合わせる
fruit_to_check = "バナナ"
if fruit_to_check in fruits:
    print(f"{fruit_to_check}は果物リストに含まれています")
else:
    print(f"{fruit_to_check}は果物リストにありません")
「りんご」は集合に含まれる? True
「メロン」は集合に含まれる? False
バナナは果物リストに含まれています

集合の特徴的な演算#

集合の最も便利な特徴は、数学の集合演算(和集合、積集合、差集合など)が簡単にできることです。

和集合(union):すべての要素を集める#

2つの集合の要素をすべて集めた新しい集合を作るには、| 演算子または union() メソッドを使います。

>
# 2つの集合
fruits1 = {"りんご", "バナナ", "オレンジ"}
fruits2 = {"バナナ", "キウイ", "マンゴー"}

# 和集合(すべての要素を集める)
all_fruits = fruits1 | fruits2  # 演算子を使う方法
# all_fruits = fruits1.union(fruits2)  # メソッドを使う方法

print("集合1:", fruits1)
print("集合2:", fruits2)
print("和集合(全ての要素):", all_fruits)
集合1: {'バナナ', 'オレンジ', 'りんご'}
集合2: {'キウイ', 'マンゴー', 'バナナ'}
和集合(全ての要素): {'キウイ', 'バナナ', 'マンゴー', 'オレンジ', 'りんご'}

積集合(intersection):共通の要素を見つける#

2つの集合に共通する要素だけを抽出するには、& 演算子または intersection() メソッドを使います。

>
# 2つの集合
fruits1 = {"りんご", "バナナ", "オレンジ"}
fruits2 = {"バナナ", "キウイ", "マンゴー"}

# 積集合(共通する要素)
common_fruits = fruits1 & fruits2  # 演算子を使う方法
# common_fruits = fruits1.intersection(fruits2)  # メソッドを使う方法

print("集合1:", fruits1)
print("集合2:", fruits2)
print("積集合(共通の要素):", common_fruits)
集合1: {'バナナ', 'オレンジ', 'りんご'}
集合2: {'キウイ', 'マンゴー', 'バナナ'}
積集合(共通の要素): {'バナナ'}

差集合(difference):片方にあって他方にない要素を見つける#

一方の集合から他方の集合の要素を除いた結果を得るには、- 演算子または difference() メソッドを使います。

>
# 2つの集合
fruits1 = {"りんご", "バナナ", "オレンジ"}
fruits2 = {"バナナ", "キウイ", "マンゴー"}

# 差集合(集合1にあって集合2にない要素)
fruits1_only = fruits1 - fruits2  # 演算子を使う方法
# または fruits1_only = fruits1.difference(fruits2)  # メソッドを使う方法

# 差集合(集合2にあって集合1にない要素)
fruits2_only = fruits2 - fruits1

print("集合1:", fruits1)
print("集合2:", fruits2)
print("差集合(集合1だけの要素):", fruits1_only)
print("差集合(集合2だけの要素):", fruits2_only)
集合1: {'バナナ', 'オレンジ', 'りんご'}
集合2: {'キウイ', 'マンゴー', 'バナナ'}
差集合(集合1だけの要素): {'オレンジ', 'りんご'}
差集合(集合2だけの要素): {'キウイ', 'マンゴー'}

対称差(symmetric difference):どちらか片方にだけある要素を見つける#

2つの集合のうち、どちらか一方にだけ含まれる要素を抽出するには、^ 演算子または symmetric_difference() メソッドを使います。

>
# 2つの集合
fruits1 = {"りんご", "バナナ", "オレンジ"}
fruits2 = {"バナナ", "キウイ", "マンゴー"}

# 対称差(どちらか片方にだけある要素)
exclusive_fruits = fruits1 ^ fruits2  # 演算子を使う方法
# または exclusive_fruits = fruits1.symmetric_difference(fruits2)  # メソッドを使う方法

print("集合1:", fruits1)
print("集合2:", fruits2)
print("対称差(片方にだけある要素):", exclusive_fruits)
集合1: {'バナナ', 'オレンジ', 'りんご'}
集合2: {'キウイ', 'マンゴー', 'バナナ'}
対称差(片方にだけある要素): {'キウイ', 'マンゴー', 'オレンジ', 'りんご'}

集合の制約#

集合には次のような制約があります。

  1. 重複不可: 同じ要素を複数回追加しても、1回しか保存されません。
  2. 順序なし: 要素の順序は保証されません。順序が重要な場合は、リストを使いましょう。
  3. 変更可能な要素は不可: リストや辞書などの変更可能(ミュータブル)なオブジェクトは集合の要素として使えません。文字列、数値、タプルなどのイミュータブル(変更不可)なオブジェクトは使えます。
>
# これは正しく動作する
valid_set = {1, "hello", (1, 2, 3)}  # 数値、文字列、タプルはOK

# これはエラーになる
# invalid_set = {1, [2, 3]}  # リストを要素に含めるとエラー
# invalid_set = {1, {"a": 1}}  # 辞書を要素に含めるとエラー

集合内包表記#

リスト内包表記と同様に、集合にも内包表記があります。波括弧 {} を使い、簡潔に集合を作ることができます。辞書内包表記と似ているので、見間違いしないように注意しましょう。

>
# 1から10までの数値のうち、偶数だけの集合
even_numbers = {x for x in range(1, 11) if x % 2 == 0}
print("偶数の集合:", even_numbers)

# 文字列のリストから、各単語の長さの集合
words = ["apple", "banana", "orange", "kiwi", "grape", "pear"]
word_lengths = {len(word) for word in words}
print("単語の長さの集合:", word_lengths)
偶数の集合: {2, 4, 6, 8, 10}
単語の長さの集合: {4, 5, 6}

まとめ#

集合は重複のないデータの集まりを表すデータ構造で、次のような特徴や機能があることを学びました。

  • 重複する要素を持たない
  • 順序が保証されない
  • 要素の追加・削除が可能
  • 集合演算(和集合、積集合、差集合など)が簡単にできる
  • 重複排除や複数のデータの共通項・差分を見つけるのに便利

集合は特に「一意な値の集まりが必要なとき」や「複数のデータ間の関係を調べるとき」に役立つツールです。リスト、タプル、辞書と組み合わせて使うことで、より複雑なデータ処理を効率的に行うことができるようになります。

Pythonのデータ構造(リスト、タプル、辞書、集合)をマスターすることで、より効率的かつ読みやすいコードを書けるようになります。それぞれのデータ構造の特性を理解し、状況に応じて適切なものを選ぶことが良いプログラミングの第一歩です。