このページで解説している内容は、以下の YouTube 動画の解説で見ることができます。

【Python入門】集合を利用して値の有無を調べる

集合を利用して値の有無を調べる

 多くのアプリケーションでは、特定の値がデータ内に存在するかどうかを効率的に確認する必要があります。Pythonの集合(set)は、このような「値の有無」を高速に判定できる優れたデータ構造です。集合は重複する値を持たず、内部実装が最適化されているため、大量のデータから目的の値を探し出す際に特に有効です。
 ここでは、集合の基本的な性質とリストやタプルとの違いを理解するとともに、実際のプログラム例を通じて集合を利用した値の有無の判定方法を詳しく解説していきます。

プログラムのダウンロード

 「ダウンロード」から、JupyterLab で実行できるサンプルプログラムがダウンロードできます。ファイルは、ESET Endpoint Securityでウイルスチェックをしておりますが、ダウンロードとプログラムの実行は自己責任でお願いいたします。

1.集合の基本概念

1.1. 集合の特徴

Pythonの集合(set)は、以下のような特徴を持っています。

  • ミュータブルであること
    集合は作成後にも要素の追加や削除が可能です。
  • 重複を許さない
    同一の値が複数存在することはなく、一意な要素のみが格納されます。
  • 順序が保証されない
    集合内の要素は、格納された順序や並び順が保証されません。
  • 格納できる要素の制約
    集合にはイミュータブルな値(例えば、文字列、数値、タプルなど)だけが格納可能です。

1.2. 他のデータ構造との比較

 集合とリスト、タプルはそれぞれ異なる用途に最適化されています。以下の表は、それぞれの特徴をまとめたものです。

データ構造ミュータブル性重複の許可順序保証格納可能な値
リスト可能可能保証されるすべての型
タプル不可可能保証されるすべての型
集合可能不可保証されないイミュータブルな型のみ

 上記の表から分かるように、集合は重複を排除し、順序を必要としないデータの管理に特化しています。特に「ある値が存在するか否か」を調べる処理においては、集合の高速な探索能力が大きな利点となります。

2.集合を用いた値の有無の判定

2.1. 発送可能国のチェックを例に

 オンラインショップでは、ユーザーの入力した国が発送対象国に含まれているかを迅速に判定する必要があります。ここでは、発送可能な国を集合で管理し、入力された国がその中に存在するかをチェックするプログラム例を示します。

サンプルプログラム

# 発送可能な国の一覧を集合として定義
allowed_countries = {'USA', 'Canada', 'UK', 'Germany', 'France', 'Australia'}

# ユーザーから発送希望国を入力として受け取る
requested_country = input("発送希望国を入力してください: ")

# 入力された国が発送可能な国かどうかを集合を用いて判定
if requested_country in allowed_countries:
    print(f"{requested_country}への発送は可能です。")
else:
    print(f"{requested_country}への発送は行っておりません。")

実行結果

発送希望国を入力してください:  USA
USAへの発送は可能です。

詳しい解説

  • allowed_countries の定義
    発送可能な国を一意な要素として管理するため、集合を用いています。これにより、重複する国名が混在することなく、効率的な検索が可能となります。
  • 入力値のチェック
    if requested_country in allowed_countries: の部分では、集合の特徴を活かし、指定した国が集合内に存在するかどうかを高速に確認しています。集合は内部でハッシュテーブルを利用しているため、平均してO(1)の計算量で判定できます。
  • 柔軟な更新
    集合はミュータブルなため、例えば新たに発送対象国が増えた場合も allowed_countries.add('Japan') などのメソッドで容易に追加できます。

2.2. 高速な探索とパフォーマンスの利点

 集合を用いることで、リストやタプルと比較して、値の存在確認が非常に高速に行えます。例えば、数千や数万の要素が含まれるデータから特定の値を探し出す場合、リストだと全要素を順番に確認する必要がありますが、集合はハッシュテーブルを使うため、ほぼ一定時間で結果が得られます。この特性は、リアルタイム性が求められるシステムや大量データの処理において非常に有用です。

3.集合利用時の応用例と注意点

3.1. 応用例:アクセス権限のチェック

 ユーザーのアクセス権限を管理する際、許可されたユーザーIDの集合を用いると、ログイン時にユーザーが許可されているかどうかを迅速に判定できます。例えば、以下のようなコードが考えられます。

サンプルプログラム

# アクセス許可されたユーザーIDの集合
authorized_users = {'user123', 'admin', 'guest'}

# ログインユーザーIDの入力(実際のシステムでは認証プロセスを経由します)
current_user = input("ユーザーIDを入力してください: ")

# 入力されたユーザーIDが許可されているかどうかをチェック
if current_user in authorized_users:
    print("アクセスが許可されました。")
else:
    print("アクセスが拒否されました。")

実行結果

ユーザーIDを入力してください:  admin
アクセスが許可されました。

解説

  • ユーザーIDの集合を利用することで、許可チェックを高速に行えます。
  • この方法は、アクセスが頻繁に発生するシステムでのパフォーマンス向上に寄与します。

3.2. 集合利用時の注意点

集合を利用する際には、以下の点に留意する必要があります。

  • 順序保証がないこと
    集合は内部の要素の順序を保持しないため、順序が必要な場合はリストなど他のデータ構造を併用する必要があります。
  • 格納可能な値の制限
    集合に格納できるのはイミュータブルな値のみです。リストや他の集合など、変更可能なオブジェクトは直接格納できません。

まとめ

 ここでは、集合の特徴とその高速な探索能力を活かして、値の有無を迅速に判定する方法について解説しました。集合はミュータブルでありながら重複を許さず、ハッシュテーブルを利用することで平均して一定時間内に検索が完了するため、発送可能国やアクセス権限のチェックなど、様々な用途で効果を発揮します。データの性質や用途に応じた適切なデータ構造の選択は、プログラムの効率化に直結するため、集合の特性を理解し活用することは、より良いシステム開発につながるでしょう。