【Python】集合操作マスターへの道|重複削除から和集合・差集合まで徹底解説

2025年4月23日水曜日

Python

この記事では、Pythonの集合操作について、基本から応用までバッチリ解説していきます!

「集合ってなんか難しそう…」
「リストと何が違うの?」

と思っているプログラミング初心者の方、安心してください。

集合を使いこなせると、データ処理、特に重複の削除やグループ分けがビックリするほど簡単になるんですよ。

この記事を読めば、あなたもPython集合操作の達人になれるかも?さっそく見ていきましょう!

この記事で学べること

  • Pythonの集合(set)の基本的な考え方
  • リストやタプルとの明確な違い
  • 集合の作り方、要素の追加や削除の方法
  • 和集合、積集合、差集合などの集合演算テクニック
  • 集合操作で役立つ便利なメソッド
  • よくあるエラーとその対処法
  • 実際のプログラミングでの集合の活用アイデア

Pythonの集合(set)とはそもそも何?リストとの違いは?

まず、Pythonの集合(set)って一体何者なのか、そこから始めましょう。

簡単に言うと、集合は「順番を気にしない、重複を許さない要素の集まり」のことです。
学校で習った数学の集合に近いイメージですね。

ここでよく比較されるのがリスト(list)です。リストとの違いを見てみましょう。

  • リスト(list)
    - 順番がある(要素を取り出すときにインデックス番号を使う)
    - 同じ要素が複数あってもOK(重複OK)
    - 例: [1, 2, 2, 3]
  • 集合(set)
    - 順番がない(インデックス番号で要素を取り出せない)
    - 同じ要素は1つしか持てない(重複NG
    - 例: {1, 2, 3} (たとえ {1, 2, 2, 3} と作ろうとしても、自動で {1, 2, 3} になる)

じゃあ、どんな時に集合を使うと便利なんでしょうか?
例えば、こんな場面で活躍します。

  • アンケート結果から、回答の種類だけを知りたい時(回答者の名前が重複していても関係ない)
  • 複数のグループに共通して所属しているメンバーを探したい時
  • 大量のデータから重複しているものをサッと取り除きたい時

重複をなくしたり、グループ間の関係性を調べたりするのが得意技なんです。

集合のイメージ

  +-------+
  | Apple |
  | Banana| ----> 要素の集まり (順番は不定)
  | Orange|      (同じものは入れない)
  +-------+

集合を作成する基本的な方法

よし、集合がどんなものか分かったところで、実際にPythonで集合を作ってみましょう!
作り方は主に2つあります。

1. 波括弧 {} を使う方法

一番シンプルな方法です。要素をカンマ , で区切って波括弧で囲みます。

# 波括弧を使って集合を作成
fruits = {'apple', 'banana', 'orange'}
print(fruits)
print(type(fruits)) # 型を確認すると  と表示される

# 重複する要素を入れても自動で削除される
numbers = {1, 2, 2, 3, 4, 4, 4}
print(numbers)

実行結果

{'orange', 'banana', 'apple'}
<class 'set'>
{1, 2, 3, 4}

注意点: 空っぽの集合を作りたいときに {} と書くと、辞書(dict)型になってしまいます。空の集合を作りたい場合は、次に紹介する set() 関数を使いましょう。

# これは空の辞書になる
empty_dict = {}
print(type(empty_dict))

# 空の集合を作るには set() を使う
empty_set = set()
print(type(empty_set))

実行結果

<class 'dict'>
<class 'set'>

2. set() 関数を使う方法

set() 関数を使うと、リストやタプルなど、他のシーケンス(順番のあるデータ)から集合を作ることができます。この時も重複する要素は自動的に削除されます。

# リストから集合を作成
my_list = ['a', 'b', 'c', 'a', 'b']
my_set_from_list = set(my_list)
print(my_set_from_list)

# タプルから集合を作成
my_tuple = (10, 20, 30, 10)
my_set_from_tuple = set(my_tuple)
print(my_set_from_tuple)

# 文字列から集合を作成(各文字が要素になる)
my_string = "hello"
my_set_from_string = set(my_string)
print(my_set_from_string)

実行結果

{'c', 'a', 'b'}
{10, 20, 30}
{'o', 'l', 'h', 'e'}

set() 関数は、既存のデータから重複を除いたユニークな要素だけを取り出したい時にも便利ですね!

集合への要素の追加と削除のやり方

集合を作ったら、次は要素を追加したり、削除したりする方法を見ていきましょう。

要素を追加するaddメソッド

集合に新しい要素を1つ追加したい場合は、add() メソッドを使います。

# 集合を作成
my_set = {1, 2, 3}
print("元の集合:", my_set)

# 要素 4 を追加
my_set.add(4)
print("4を追加後:", my_set)

# すでに存在する要素 2 を追加してみる (変化なし)
my_set.add(2)
print("2を追加後:", my_set)

実行結果

元の集合: {1, 2, 3}
4を追加後: {1, 2, 3, 4}
2を追加後: {1, 2, 3, 4}

add() は、すでにある要素を追加しようとしても、エラーにはならず、集合の中身も変わりません。重複を許さないという集合の性質通りですね。

要素を削除するremovediscardpopメソッド

要素を削除する方法はいくつかあります。状況によって使い分けましょう。

1. remove() メソッド: 指定した要素を削除(要素がないとエラー)

remove() は、指定した要素を集合から削除します。ただし、もし指定した要素が集合の中に存在しない場合、エラー(KeyError)が発生します

my_set = {'apple', 'banana', 'orange'}
print("元の集合:", my_set)

# 'banana' を削除
my_set.remove('banana')
print("'banana'削除後:", my_set)

# 存在しない 'grape' を削除しようとするとエラーになる
# my_set.remove('grape') # -> KeyError: 'grape'

実行結果

元の集合: {'orange', 'banana', 'apple'}
'banana'削除後: {'orange', 'apple'}
# 次の行はコメントアウトしないとエラーで止まる

確実に消したい要素があって、もしその要素がなかったらエラーとして知らせてほしい場合に使うと良いでしょう。

2. discard() メソッド: 指定した要素を削除(要素がなくてもエラーにならない)

discard() も指定した要素を削除しますが、remove() と違って、指定した要素が集合の中に存在しなくても、エラーになりません。何も起こらずスルーされます。

my_set = {'apple', 'banana', 'orange'}
print("元の集合:", my_set)

# 'banana' を削除
my_set.discard('banana')
print("'banana'削除後:", my_set)

# 存在しない 'grape' を削除しようとしてもエラーにならない
my_set.discard('grape')
print("'grape'削除試行後:", my_set) # 集合は変化しない

実行結果

元の集合: {'orange', 'banana', 'apple'}
'banana'削除後: {'orange', 'apple'}
'grape'削除試行後: {'orange', 'apple'}

要素があるかどうか分からないけど、あれば削除したい、という場合に安全に使えるメソッドです。

3. pop() メソッド: ランダムな要素を削除して、その要素を返す

pop() は、集合からどれか1つの要素をランダム(※実際には実装依存で必ずしもランダムではないですが、予測不能な要素)に取り出して削除し、その取り出した要素を返します。集合は順序がないので、どの要素が取り出されるかは分かりません。

my_set = {'apple', 'banana', 'orange', 'melon'}
print("元の集合:", my_set)

# pop() で要素を1つ取り出して削除
removed_element = my_set.pop()
print("削除された要素:", removed_element)
print("pop()実行後の集合:", my_set)

removed_element_2 = my_set.pop()
print("削除された要素:", removed_element_2)
print("pop()実行後の集合:", my_set)

# 空の集合に対して pop() を実行するとエラーになる
# empty_set = set()
# empty_set.pop() # -> KeyError: 'pop from an empty set'

実行結果 (実行するたびに削除される要素が変わる可能性があります):

元の集合: {'melon', 'banana', 'orange', 'apple'}
削除された要素: melon
pop()実行後の集合: {'banana', 'orange', 'apple'}
削除された要素: banana
pop()実行後の集合: {'orange', 'apple'}

特定の要素ではなく、とりあえず集合からどれか1つ要素を取り出したい場合に利用できますが、どの要素が選ばれるか予測できない点には注意しましょう。

集合操作の真骨頂!集合演算を使いこなす

さあ、ここからが集合操作の本番です!複数の集合を使って、足したり引いたり、共通部分を見つけたりする「集合演算」を見ていきましょう。
数学でやったベン図を思い出すと分かりやすいかもしれませんね。

和集合(union)グループを結合する

和集合(わしゅうごう)は、複数の集合に含まれる全ての要素を、重複を除いて集めた新しい集合を作る操作です。いわば「集合の足し算」みたいなものです。
演算子 | (パイプ) または union() メソッドを使います。

  +---+---+---+
  | A |AB | B |   <-- AとBの全ての要素 (重複なし)
  +---+---+---+
set_a = {1, 2, 3, 4}
set_b = {3, 4, 5, 6}
set_c = {6, 7, 8}

# 演算子 | を使う
union_ab = set_a | set_b
print(f"A | B: {union_ab}")

# union() メソッドを使う
union_ab_method = set_a.union(set_b)
print(f"A.union(B): {union_ab_method}")

# 複数の集合の和集合も可能
union_abc = set_a | set_b | set_c
# または union_abc = set_a.union(set_b, set_c)
print(f"A | B | C: {union_abc}")

実行結果

A | B: {1, 2, 3, 4, 5, 6}
A.union(B): {1, 2, 3, 4, 5, 6}
A | B | C: {1, 2, 3, 4, 5, 6, 7, 8}

set_aset_b の両方に含まれる 34 も、結果の集合では1つだけになっている点に注目してください。

積集合(intersection)共通部分を見つける

積集合(せきしゅうごう)は、複数の集合に共通して含まれる要素だけを集めた新しい集合を作る操作です。「共通点探し」ですね。
演算子 & (アンパサンド) または intersection() メソッドを使います。

  +---+---+---+
  | A |AB | B |   <-- AとBの両方に含まれる要素
  +---+---+---+
set_a = {1, 2, 3, 4}
set_b = {3, 4, 5, 6}
set_c = {4, 5, 9}

# 演算子 & を使う
intersection_ab = set_a & set_b
print(f"A & B: {intersection_ab}")

# intersection() メソッドを使う
intersection_ab_method = set_a.intersection(set_b)
print(f"A.intersection(B): {intersection_ab_method}")

# 複数の集合の積集合も可能
intersection_abc = set_a & set_b & set_c
# または intersection_abc = set_a.intersection(set_b, set_c)
print(f"A & B & C: {intersection_abc}") # 3つ全てに共通するのは 4 だけ

実行結果

A & B: {3, 4}
A.intersection(B): {3, 4}
A & B & C: {4}

set_aset_b の両方に含まれる 34 だけが取り出されています。

差集合(difference)片方だけに存在する要素

差集合(さしゅうごう)は、ある集合から、別の集合に含まれる要素を取り除いた残りの要素を集めた新しい集合を作る操作です。「引き算」のようなイメージです。
演算子 - (ハイフン) または difference() メソッドを使います。注意点として、A - BB - A では結果が変わります

  +---+---+---+
  | A |AB | B |   <-- AにあってBにない要素
  +---+---+---+
set_a = {1, 2, 3, 4}
set_b = {3, 4, 5, 6}

# 演算子 - を使う (A から B の要素を除く)
difference_a_b = set_a - set_b
print(f"A - B: {difference_a_b}") # A にあって B にないもの

# 演算子 - を使う (B から A の要素を除く)
difference_b_a = set_b - set_a
print(f"B - A: {difference_b_a}") # B にあって A にないもの

# difference() メソッドを使う (A から B の要素を除く)
difference_a_b_method = set_a.difference(set_b)
print(f"A.difference(B): {difference_a_b_method}")

実行結果

A - B: {1, 2}
B - A: {5, 6}
A.difference(B): {1, 2}

set_a - set_b では、set_a の要素 {1, 2, 3, 4} から set_b にも含まれる {3, 4} が取り除かれ、{1, 2} が残ります。

対称差(symmetric_difference)どちらか一方にだけ存在する要素

対称差(たいしょうさ)は、2つの集合のうち、どちらか一方にだけ含まれる要素を集めた新しい集合を作る操作です。つまり、和集合から積集合(共通部分)を取り除いたものです。「お互いに持っていないもの」を集めるイメージです。
演算子 ^ (キャレット、ハット) または symmetric_difference() メソッドを使います。

  +---+---+---+
  | A |AB | B |   <-- Aだけにある要素とBだけにある要素
  +---+---+---+
set_a = {1, 2, 3, 4}
set_b = {3, 4, 5, 6}

# 演算子 ^ を使う
symmetric_diff_ab = set_a ^ set_b
print(f"A ^ B: {symmetric_diff_ab}") # (A - B) | (B - A) と同じ

# symmetric_difference() メソッドを使う
symmetric_diff_ab_method = set_a.symmetric_difference(set_b)
print(f"A.symmetric_difference(B): {symmetric_diff_ab_method}")

実行結果

A ^ B: {1, 2, 5, 6}
A.symmetric_difference(B): {1, 2, 5, 6}

set_a だけにある {1, 2} と、set_b だけにある {5, 6} が合わさった結果になっていますね。

集合操作で知っておくと便利なメソッド

基本的な集合演算以外にも、集合を扱う上で便利なメソッドがいくつかあります。ここでは代表的なものをいくつか紹介しましょう。

  • issubset(other) または <=:
    自分の集合が、引数 other の集合に完全に含まれているか(部分集合か)を判定します (True/False)。< は真部分集合(完全に含まれ、かつ要素数が少ない)かを判定します。
    set_a = {1, 2}
    set_b = {1, 2, 3}
    set_c = {1, 2}
    print(set_a.issubset(set_b)) # True
    print(set_a <= set_b)      # True
    print(set_a < set_b)       # True (set_aの方が要素が少ない)
    print(set_a <= set_c)      # True
    print(set_a < set_c)       # False (要素数が同じ)
      
  • issuperset(other) または >=:
    自分の集合が、引数 other の集合を完全に含んでいるか(上位集合か)を判定します (True/False)。> は真上位集合(完全に含み、かつ要素数が多い)かを判定します。
    set_a = {1, 2, 3}
    set_b = {1, 2}
    set_c = {1, 2, 3}
    print(set_a.issuperset(set_b)) # True
    print(set_a >= set_b)      # True
    print(set_a > set_b)       # True (set_aの方が要素が多い)
    print(set_a >= set_c)      # True
    print(set_a > set_c)       # False (要素数が同じ)
      
  • isdisjoint(other):
    自分の集合と、引数 other の集合に、共通の要素が一つも無いか(互いに素か)を判定します (True/False)。
    set_a = {1, 2}
    set_b = {3, 4}
    set_c = {2, 5}
    print(set_a.isdisjoint(set_b)) # True (共通要素なし)
    print(set_a.isdisjoint(set_c)) # False (共通要素 2 がある)
      
  • update(other) または |=:
    自分の集合に、引数 other の集合の要素を全て追加します(和集合で自分自身を更新)。union() と似ていますが、新しい集合を作らず、元の集合を変更します。
    set_a = {1, 2}
    set_b = {2, 3, 4}
    set_a.update(set_b) # set_a |= set_b と同じ
    print(set_a) # {1, 2, 3, 4}
      
  • intersection_update(other) または &=:
    自分の集合を、引数 other の集合との共通要素だけで更新します(積集合で自分自身を更新)。
    set_a = {1, 2, 3, 4}
    set_b = {3, 4, 5}
    set_a.intersection_update(set_b) # set_a &= set_b と同じ
    print(set_a) # {3, 4}
      
  • difference_update(other) または -=:
    自分の集合から、引数 other の集合にも含まれる要素を削除します(差集合で自分自身を更新)。
    set_a = {1, 2, 3, 4}
    set_b = {3, 4, 5}
    set_a.difference_update(set_b) # set_a -= set_b と同じ
    print(set_a) # {1, 2}
      
  • symmetric_difference_update(other) または ^=:
    自分の集合を、引数 other の集合との対称差で更新します(どちらか一方にだけ含まれる要素で自分自身を更新)。
    set_a = {1, 2, 3, 4}
    set_b = {3, 4, 5, 6}
    set_a.symmetric_difference_update(set_b) # set_a ^= set_b と同じ
    print(set_a) # {1, 2, 5, 6}
      
  • clear():
    集合の全ての要素を削除し、空の集合にします。
    set_a = {1, 2, 3}
    set_a.clear()
    print(set_a) # set()
      

これらのメソッドを使いこなせると、より複雑な集合操作もスマートに書けるようになりますよ!

集合操作でよくあるエラーと注意点

集合操作は便利ですが、いくつか注意点や、初心者がハマりやすいポイントがあります。ここでしっかり押さえておきましょう!

1. 集合に入れられるのは「変更不可(immutable)」なものだけ

集合の要素になれるのは、数値、文字列、タプルなど、後から中身を変更できないデータ型だけです。リストや他の集合、辞書のような「変更可能(mutable)」なものを要素として追加しようとすると、TypeError というエラーになります。

# これはOK
my_set = {1, "hello", (1, 2)}
print(my_set)

# リストを要素にしようとするとエラー
# error_set = {1, 2, [3, 4]} # TypeError: unhashable type: 'list'

もしリストのようなものを集合で管理したい場合は、一度タプルに変換するなどの工夫が必要です。

2. remove() で存在しない要素を消そうとするとエラー

先ほども触れましたが、remove() メソッドは、削除しようとした要素が集合内にないと KeyError を発生させます。「あるはず!」と思って使ったらエラーが出た、というケースはよくあります。
エラーを避けたい場合は、要素が存在するかどうかを in 演算子で事前にチェックするか、discard() メソッドを使うのが安全です。

my_set = {'apple', 'banana'}

# 事前にチェック
if 'orange' in my_set:
    my_set.remove('orange')
else:
    print("'orange' は見つかりませんでした。")

# または discard を使う
my_set.discard('orange') # エラーにならない
print(my_set)

実行結果

'orange' は見つかりませんでした。
{'banana', 'apple'}

3. 集合には順番がないことを忘れない!

これも大事なポイントです。集合は要素の順番を保持しません。そのため、リストのようにインデックス番号(例: my_list[0])で要素を取り出すことはできません。

my_set = {10, 20, 30}
# print(my_set[0]) # TypeError: 'set' object is not subscriptable (インデックス指定不可)

# 要素を取り出したい場合は、forループなどを使う
for item in my_set:
    print(item)

実行結果 (表示順は実行ごとに変わる可能性あり):

10
20
30

順番が結果に影響するような処理には、リストやタプルを使うようにしましょう。

集合操作の活用例 - データ処理を効率化しよう

さて、集合操作の基本が分かったところで、実際にどんな場面で役立つのか、具体的な活用例を見てみましょう。

活用例1: リストの重複要素を削除する

これは集合の最も代表的な使い方の1つです。リストを一度 `set()` 関数で集合に変換し、それをまたリストに戻すだけで、簡単に重複を取り除けます。

# 重複を含むリスト
my_list = [1, 2, 3, 2, 4, 5, 1, 4, 6]

# 集合に変換して重複を削除し、リストに戻す
unique_list = list(set(my_list))

print("元のリスト:", my_list)
print("重複削除後:", unique_list)

実行結果

元のリスト: [1, 2, 3, 2, 4, 5, 1, 4, 6]
重複削除後: [1, 2, 3, 4, 5, 6]

数行のコードでスッキリ書けますね!

活用例2: 2つのリストに共通する要素を見つける

例えば、イベントAの参加者リストとイベントBの参加者リストがあって、両方に参加した人を見つけたい場合、積集合が役立ちます。

event_a_attendees = ['Alice', 'Bob', 'Charlie', 'David']
event_b_attendees = ['Charlie', 'Eve', 'Alice', 'Frank']

# それぞれを集合に変換
set_a = set(event_a_attendees)
set_b = set(event_b_attendees)

# 積集合で共通の参加者を見つける
common_attendees = set_a & set_b # または set_a.intersection(set_b)

print("イベントA参加者:", set_a)
print("イベントB参加者:", set_b)
print("両イベント参加者:", common_attendees)

実行結果

イベントA参加者: {'David', 'Bob', 'Alice', 'Charlie'}
イベントB参加者: {'Eve', 'Frank', 'Alice', 'Charlie'}
両イベント参加者: {'Alice', 'Charlie'}

活用例3: あるリストにしか含まれない要素を見つける

昨日のアクセスユーザーリストと今日のアクセスユーザーリストがあって、今日初めてアクセスしたユーザー(昨日のリストにはいないユーザー)を知りたい場合、差集合が使えます。

yesterday_users = {'user1', 'user2', 'user3', 'user4'}
today_users = {'user2', 'user3', 'user5', 'user6'}

# 今日のユーザーから昨日のユーザーを引く (差集合)
new_users_today = today_users - yesterday_users # または today_users.difference(yesterday_users)

print("昨日のユーザー:", yesterday_users)
print("今日のユーザー:", today_users)
print("今日初めてアクセスしたユーザー:", new_users_today)

実行結果

昨日のユーザー: {'user3', 'user4', 'user1', 'user2'}
今日のユーザー: {'user5', 'user6', 'user3', 'user2'}
今日初めてアクセスしたユーザー: {'user5', 'user6'}

このように、集合演算を使うことで、リストのループ処理などで複雑になりがちな処理を、簡潔かつ効率的に記述できる場合が多いのです。

【まとめ】Python集合操作をマスターしよう

お疲れ様でした!今回はPythonの集合(set)操作について、基本的なところから応用的な使い方まで、一通り解説してきました。

今回のポイントをおさらいしましょう

  • 集合は順番がなく、重複を許さない要素の集まり。
  • {}set() で作成できる(空集合は set() で!)。
  • add() で要素を追加、remove()discard() で削除できる。
  • 和集合 |, 積集合 &, 差集合 -, 対称差 ^ などの集合演算が強力!
  • 部分集合か判定する issubset() など、便利なメソッドも色々ある。
  • 要素は変更不可なものだけ、順序がない点に注意する。
  • 重複削除やグループ比較など、データ処理で大活躍する。

集合は、リストや辞書ほど頻繁に使うことはないかもしれませんが、知っていると特定の場面でコードが劇的にシンプルになったり、処理速度が向上したりします。

ぜひ、この記事で学んだことを活かして、実際のコードで集合を使ってみてください。
まずは簡単な重複削除から試してみるのがおすすめです!

Pythonのデータ構造をうまく使い分けることが、効率的で読みやすいコードを書くための近道です。集合操作をマスターして、あなたのPythonスキルをさらにレベルアップさせていきましょう!

【関連記事】 「Pythonとは?」に答える最初の一歩

このブログを検索

  • ()

自己紹介

自分の写真
リモートワークでエンジニア兼Webディレクターとして活動しています。プログラミングやAIなど、日々の業務や学びの中で得た知識や気づきをわかりやすく発信し、これからITスキルを身につけたい人にも役立つ情報をお届けします。 note → https://note.com/yurufuri X → https://x.com/mnao111

QooQ