きり丸の技術日記

技術検証したり、資格等をここに残していきます。

Pythonで配列から特定のキーだけで検索したい時は辞書型を経由すると速い

当たり前の話ではありますが。

Userクラスの配列からuser_idをキーに検索したい、emailをキーに検索したい等々の特定のキーがある場合、辞書型を経由すると非常に早く値を取得できます。

前提

  • Python 3.9

対応

配列を辞書型に変換する

最初にUserクラスを定義します。

class User:
    def __init__(self, user_id):
        self.user_id = user_id

    user_id: str

作成したUserクラスを元にuser_idをkeyとして、valueがUserクラスの辞書型を作成します。

# ユーザ配列の作成
users = [User(user_id=str(x)) for x in range(100)]
# user_idをkeyとし、valueを元のユーザとする
user_dict: Dict[str, User] = {x.user_id: x for x in users}

検索する

後は辞書型の検索を行います。

user_dict.get('1')

後続の処理でNoneチェックをしたくない場合は、取得失敗した時のデフォルト値を入れてください。

user_dict.get('1', User(user_id='XXXX'))

配列のまま検索(ChatGPT3.5の回答)

ChatGPT3.5に回答を依頼すると、配列の処理中にif文を使用する方法が回答されました。Python 3エンジニア認定基礎試験でも、配列から目的の値だけを取得する方法はこちらだった記憶があります。

[x for x in users if x.user_id == '1']

処理速度の差

10万配列から100回検索をしました。サンプルコードは次のとおりです。

def test_01():
    processingTime: float = 0
    for y in range(10):
        start = time.perf_counter()

        a = [User(user_id=str(x)) for x in range(100000)]

        for x in range(100):
            [x for x in a if x.user_id == str(random.randrange(100000))]

        end = time.perf_counter()
        processingTime += end - start

    print(processingTime / 10)
# 処理時間(100回検索)
# 配列のまま
7.498883651900087
# 辞書のまま
0.17779069980001622

参考程度に1回だけ実行した場合でも辞書型への変換コストを含めても辞書型で検索した方が早かったです。

# 処理時間(100回検索)
# 配列のまま
0.2368281210000532
# 辞書のまま
0.19582450180000704

ソースコード

テストコードで動作確認しています。

終わりに

今までは配列から特定のキーを元に辞書型を作る方法を知らずに、愚直に処理していました。

Javaだと意識することが無かったのですが、本当はちゃんと変換した方が良かったんですかね。JITコンパイルで最適化されている気がしますが、裏付けはありません。

今後も、Pythonではきちんと計算速度を意識して処理していきたいです。