Python速習ガイド - ステップ1 基本的な文法とデータ型 (10) - 集合
- 本講座は、Pythonプログラミングの基礎を手を動かしながら最速で身につけるための講座です。
- 「スタイルガイド」では、Pythonできれいなコードを書くためのガイドライン(PEP8)で紹介されている内容を主に記載しています。
- 各コードは実行して結果を確認することができます。
ページの再読み込みで元の内容に戻りますので、自由にいじってみてください。
「ステップ1 基本的な文法とデータ型」の続きです。
1.5. データをまとめる
1.5.4. 集合
リスト、タプル、辞書に続く、データをまとめるデータ型として「集合 (set
)」があります。
集合は重複のない要素の集まりで、順序が存在しません。
集合の作成方法
- 集合は波括弧(
{
,}
)内に要素をカンマ(,
)区切りで並べて作成します。 - 辞書との違いは、
キー: 値
のペアではなく、値だけを並べる点です。
- 空の集合は
set()
で作成します。{}
は空の辞書になるため注意してください。
set
関数を使用してリストやタプルから集合を作成することもできます。
- カンマ(
,
)の後にはスペースを1個分空けましょう。
- 長い集合の場合は複数行に分けると読みやすくなります。
- 各要素は行の先頭に スペース4個分 の字下げ(インデント)を追加します。
- 最後の要素の後ろにもカンマを入れましょう。
好きなフルーツを3つ以上含む集合 my_fruits
を作成してみましょう。
また、set()
関数を使用して同じ内容の集合を作成してください。
集合の特徴
集合には以下のような特徴があります:
- 要素の重複がない: 同じ値は1つしか保存されません
- 順序がない: 要素に順序は存在せず、インデックスによるアクセスなどはできません
- 変更可能(ミュータブル): 要素の追加や削除が可能です
- ハッシュ化可能な値のみ要素にできる: 辞書のキーと同様、基本的にイミュータブル(変更不可)なオブジェクトのみ要素にできます
要素の重複がない
順序がない
変更可能(ミュータブル)
リストや辞書と同様に、集合もミュータブル(変更可能)な型です。
集合の操作についてこのあと紹介します。
ハッシュ化可能な値のみ要素にできる
辞書のキーと同様に、集合には ハッシュ化可能な値 のみを含めることができます。
- 以下のイミュータブル(変更不可)な型が使えます:
- 数値 (
int
,float
) - 文字列 (
str
) - タプル (
tuple
) - 中に含まれるすべての要素もハッシュ化可能である場合 - ブール値 (
bool
) None
- 数値 (
- 以下のミュータブル(変更可能)な型は集合の要素として使用できません:
- リスト (
list
) - 辞書 (
dict
) - 集合 (
set
)
- リスト (
集合の基本的な操作
サイズを取得
リストと同様に、len
関数を用いて集合のサイズを取得することができます。
要素の追加 (add
)
add
メソッドを使って集合に要素を追加できます。
要素の削除 (remove
, discard
)
remove
メソッドは指定した要素を削除しますが、要素が存在しない場合はエラーになります。discard
メソッドも要素を削除しますが、要素が存在しなくてもエラーになりません。
要素の取り出し (pop
)
pop
メソッドは集合から任意の要素を取り出して削除します。- 集合には順序がないため、どの要素が取り出されるかは予測できません。
空集合(set()
)からpop
しようとすると KeyError
が発生します。
存在チェック (in
, not in
)
- リストや辞書と同様に、
in
とnot in
演算子を使って要素の存在をチェックできます。
集合演算
集合には様々な演算が定義されています。
和集合 (|
演算子)
- 2つの集合のすべての要素を含む新しい集合を作成します。
積集合 (&
演算子)
- 2つの集合の共通要素だけを含む新しい集合を作成します。
差集合 (-
演算子)
- 1つ目の集合から2つ目の集合の要素を除いた新しい集合を作成します。
対称差集合 (^
演算子)
- 2つの集合のいずれか一方にのみ含まれる要素を持つ新しい集合を作成します。
集合のその他メソッドや演算子
集合のコピー (copy
)
- リストや辞書と同様に、
copy
メソッドで集合の(浅い)コピーを作成できます。
集合の更新 (update
, |=
)
- 辞書と同様に
update
メソッドを使うと、既存の集合を別の集合との和集合で更新します。
|
演算子を使って値を更新する|=
を使っても同様の操作が可能です。
(足し算を使って値を更新する+=
などと同様の省略形です)
その他の省略形 (&=
, -=
, ^=
)
&=
を使うと、既存の集合を別の集合との共通要素だけに更新します。
-=
を使うと、既存の集合から別の集合の要素を除去します。
^=
を使うと、既存の集合と別の集合いずれか一方にのみ存在する要素の集合に更新されます。
リストへの型変換
list
関数を使用して、集合をリストに変換できます。
sorted
関数を使用すると、集合をソートされたリストに変換できます。
(要素間に順序が定義されている場合のみ)
bool
関数による型変換
- 集合に
bool
関数を適用すると、空の集合はFalse
、それ以外はTrue
を返します。
これまで学んだデータ型は、それぞれ異なる特徴と適した用途があります。
-
集合 (
set
) を使うのが適切な場合:- 重複を排除したい場合
- 要素の有無を頻繁に調べる場合
- 複数のデータの共通要素や差分を見つけたい場合
- 順序が重要でない場合
-
リスト (
list
) を使うのが適切な場合:- データの順序が重要な場合
- 要素を追加、削除、変更する必要がある場合
- 同じ値の要素を複数持ちたい場合
- インデックスでアクセスしたい場合
-
タプル (
tuple
) を使うのが適切な場合:- データが変更されない場合
- 辞書のキーや集合の要素として使用したい場合
- 関連データをグループ化したい場合
- データの順序が重要な場合
-
辞書 (
dict
) を使うのが適切な場合:- キーと値のペアでデータを管理したい場合
- キーで素早く値を取得したい場合
- データに意味のあるラベルを付けたい場合
それぞれの特性を理解し、状況に応じて適切なデータ型を選択することが重要です。
集合のまとめ
集合(set
)は、重複のない要素の集まりを表すデータ型で、様々な演算が定義されています。
主な特徴:
- 重複する要素を持たない
- 順序が定義されていない
- 変更可能(要素の追加・削除ができる)
- ハッシュ可能な値のみ要素にできる
主な操作:
.add()
: 要素を追加する.remove()
: 要素を削除する(要素がない場合はエラー).discard()
: 要素を削除する(要素がなくてもエラーにならない).pop()
: 任意の要素を取り出して削除する
集合演算:
- 和集合 (
|
): 2つの集合のすべての要素を含む集合 - 積集合 (
&
): 2つの集合の共通要素だけを含む集合 - 差集合 (
-
): 1つ目の集合から2つ目の集合の要素を除いた集合 - 対称差集合 (
^
): 2つの集合のいずれか一方にのみ含まれる要素を持つ集合
集合演算を使って、以下の問題を解きましょう。
-
フルーツの名前が含まれる2つの集合
fruits1
,fruit2
があります:fruits1 = {"apple", "banana", "orange", "grape"}
fruits2 = {"grape", "kiwi", "melon", "banana"}
-
両方の集合を合わせた集合を作成してください
-
fruits1
にあってfruits2
にない果物の集合を作成してください -
どちらか一方の集合にだけ含まれる果物の集合を作成してください
解答例
あなたはウェブサイトの分析担当者です。先週と今週の訪問者IDのリストがあります。
このデータに関して以下の分析を行いましょう。
- 先週と今週の「ユニークな」訪問者数と訪問者IDのリストをそれぞれ出力してください
101
は自分のIDでした。そのため、このIDは以降の分析対象から除外します- 先週と今週の両方で訪問したユーザー数を出力してください
- 今週だけ訪問した(先週は訪問していない)ユーザーの人数を出力してください
- 先週と今週を合わせて、何人のユニークな訪問者がいたかを出力してください
- 先週だけ訪問した(今週は訪問していない)ユーザーの集合を出力してください
解答例
集合の操作についても計算量を詳しく見てみましょう。
Pythonの集合はハッシュテーブルを内部で使用しているため、辞書と同様に多くの操作が高速です。
特に要素の存在チェック(in
演算子)はリストと比較して非常に効率的です。
※ 表中の計算量の意味:
O(1)
:入力サイズに関係なく、一定時間で処理されるO(n)
:最悪の場合、集合内の要素数n
に比例した時間がかかるO(m)
:2つ目の入力集合の要素数m
に比例した時間がかかる
操作 | 計算量 | 説明 |
---|---|---|
x in s |
O(1)(平均) | 通常は定数時間だが、多数のハッシュ衝突が発生した場合は O(n) になる可能性がある |
len(s) |
O(1) | 集合のサイズは内部カウンタで保持されているため常に定数時間 |
s.add(x) |
O(1)(平均) | 通常は定数時間だが、ハッシュ衝突や内部再配置が必要な場合は O(n) になることがある |
s.remove(x) 、s.discard(x) |
O(1)(平均) | 要素の検索と削除は通常定数時間だが、ハッシュ衝突の場合は O(n) になる可能性がある |
s.pop() |
O(1)(平均) | 任意の要素を取り出すのは通常定数時間だが、内部状態によってはO(n)になることがある |
s | t |
O(n+m) | 両方の集合の要素を調べる必要があるため、両方のサイズの合計に比例 |
s & t |
O(min(n,m)) | 小さい方の集合の各要素について大きい方の集合に含まれるか確認するため、小さい方のサイズに比例 |
s - t |
O(n) | 第1集合の各要素について第2集合に含まれるか確認するため、第1集合のサイズに比例 |
s ^ t |
O(n+m) | 両方の集合を調べる必要があるため、両集合のサイズの合計に比例 |
s.update(t) |
O(m)(平均) | 追加する集合のサイズに比例するが、リハッシュが必要な場合は O(n+m) になる |
s.copy() |
O(n) | すべての要素のシャローコピーを行うため、要素数に比例 |
特に、大きなデータセットから重複を除去したり、要素の存在をチェックしたりする場合には、
リストではなく集合を使用すると大幅にパフォーマンスが向上します。