Pythonでデータを扱う際、リストの要素を特定のルールに従って並び替えたい場面は頻繁に発生します。
標準的な昇順や降順のソートだけでなく、要素の長さや辞書の特定の値に基づいた並び替えが必要になることも少なくありません。
そのような複雑な並び替えをシンプルに実現するために用意されているのが、Pythonのソート機能におけるkey引数です。
この記事では、sortメソッドやsorted関数でkey引数を使いこなし、ラムダ式を組み合わせることで柔軟なソート処理を行う方法を詳しく解説します。
Pythonにおけるソートの基本とkey引数の役割
Pythonにはリストそのものを書き換えるlist.sort()メソッドと、新しいリストを返すsorted()関数の2種類が存在します。
これらはいずれもデフォルトでは数値の大小や文字列の辞書順で並び替えを行いますが、「何に注目して並び替えるか」を自由に指定できるのがkey引数です。
key引数には、リストの各要素が比較される前に適用される「関数」を渡します。
例えば、文字列のリストを「文字の長さ」で並び替えたい場合、組み込み関数のlenをkeyに指定します。
# 文字列のリストを定義
words = ["Python", "Go", "Java", "JavaScript", "C++"]
# 文字の長さ(len)を基準にソート
sorted_words = sorted(words, key=len)
print(sorted_words)
['Go', 'C++', 'Java', 'Python', 'JavaScript']
この例では、各要素にlen()が適用され、その結果得られた数値(2, 6, 4, 10, 3)を元に並び替えが行われています。
元の要素そのものではなく、関数の戻り値を比較基準にする点がkey引数の大きな特徴です。
ラムダ式(lambda)を活用した柔軟な条件指定
組み込み関数だけで対応できない複雑な条件でソートしたい場合は、ラムダ式(無名関数)を使用するのが一般的です。
ラムダ式を使うことで、その場限りの短い関数を定義し、key引数に渡すことができます。
辞書のリストを特定の値でソートする
実務で非常によく使われるのが、辞書を要素に持つリストのソートです。
例えば、ユーザー情報が含まれるリストを年齢順に並び替える場合は次のように記述します。
# ユーザー情報のリスト
users = [
{"name": "田中", "age": 30},
{"name": "佐藤", "age": 25},
{"name": "鈴木", "age": 35}
]
# ageキーの値を基準にソート
users.sort(key=lambda x: x["age"])
print(users)
[{'name': '佐藤', 'age': 25}, {'name': '田中', 'age': 30}, {'name': '鈴木', 'age': 35}]
lambda x: x["age"]という記述は、「リストの各要素(辞書)をxとして受け取り、そのx["age"]の値を比較に使う」という意味になります。
この手法を使えば、APIから取得したデータやデータベースのレコードのような複雑な構造も簡単に整理できます。
大文字・小文字を区別せずにソートする
デフォルトの文字列ソートでは、アルファベットの大文字が小文字よりも先に配置されます。
これを無視して純粋なアルファベット順にしたい場合、str.lowerメソッドをkeyに指定します。
chars = ["b", "A", "d", "C"]
# 大文字・小文字を区別せずソート
sorted_chars = sorted(chars, key=lambda s: s.lower())
print(sorted_chars)
['A', 'b', 'C', 'd']
複数条件を組み合わせた高度なソート
Pythonのソートにおいて非常に強力なのが、複数の条件を優先順位付きで指定できる点です。
key引数にタプルを返す関数を指定すると、タプルの第1要素で比較し、同じ値であれば第2要素で比較するという挙動になります。
# (点数, 名前) のタプルリスト
students = [
(80, "Sato"),
(90, "Tanaka"),
(80, "Abe"),
(90, "Ito")
]
# 第1条件:点数(降順にするためマイナスをつける)、第2条件:名前(昇順)
students.sort(key=lambda x: (-x[0], x[1]))
print(students)
[(90, 'Ito'), (90, 'Tanaka'), (80, 'Abe'), (80, 'Sato')]
数値データの場合、上記のように-(マイナス)を付与することで、その項目だけ逆順(降順)にすることが可能です。
このように、ラムダ式とタプルを組み合わせることで、複雑な並び替えロジックを1行で記述できます。
operatorモジュールによるパフォーマンス最適化
大量のデータをソートする場合、ラムダ式よりも標準ライブラリのoperatorモジュールを使用する方が高速に動作することがあります。
特に辞書のキーやオブジェクトの属性にアクセスする場合、itemgetterやattrgetterが推奨されます。
from operator import itemgetter
data = [
{"id": 3, "val": "C"},
{"id": 1, "val": "A"},
{"id": 2, "val": "B"}
]
# itemgetterを使って"id"でソート
data.sort(key=itemgetter("id"))
print(data)
[{'id': 1, 'val': 'A'}, {'id': 2, 'val': 'B'}, {'id': 3, 'val': 'C'}]
itemgetter("id")は内部的に高速化されており、数万件規模のデータを扱う際には有意な速度差が出るため、覚えておくと役立ちます。
コードの可読性と実行速度のバランスを考えて、適切な方を選択しましょう。
まとめ
Pythonのソートにおけるkey引数は、データの並び替えを自由自在に制御するための鍵となる機能です。
単純な組み込み関数の利用から、ラムダ式を用いたカスタムロジック、さらにはoperatorモジュールによる高速化まで、その活用範囲は多岐にわたります。
特に多次元リストや辞書のリストを扱う場面では、key引数を使いこなせるかどうかがコードの品質を左右します。
まずは基本的なラムダ式の書き方からマスターし、複雑な条件指定にも挑戦してみてください。
柔軟なソート処理を習得することで、データ処理の効率が飛躍的に向上するはずです。
