INDEX
リストのソート

Pythonのリスト(配列)に格納されたデータを特定の規則に従って並べ替える操作をソート(Sort)と呼びます。
数値を大きさ順に並べたり、文字列を辞書順や文字数順に整理したりする処理は、データ分析やアプリケーション開発で頻繁に行われます。Pythonには、リスト自体を直接書き換える sort() メソッドと、元のリストを保護したまま新しいリストを作る sorted() 関数の2つのアプローチが用意されています。本記事では、この2つの使い分けから実務で役立つカスタムソート、ソートの安定性といった高度な仕様までを網羅して解説します。
sort() メソッドと sorted() 関数の決定的な違い
どちらもデータを並べ替える機能ですが、メモリ上の挙動と元のデータに与える影響(破壊性)が根本的に異なります。
# パターン1: リスト自体を書き換える「sort()メソッド」(破壊的)
numbers = [5, 2, 9, 1, 5, 6]
# 戻り値(返り値)はNoneです。リストそのものが書き換わります。
numbers.sort()
print(numbers) # 出力: [1, 2, 5, 5, 6, 9]
# パターン2: 新しいリストを生成する「sorted()関数」(非破壊的)
origin_numbers = [5, 2, 9, 1, 5, 6]
# 元のデータをコピーし、ソートされた「新しいリスト」が返されます。
new_sorted_list = sorted(origin_numbers)
print(new_sorted_list) # 出力: [1, 2, 5, 5, 6, 9] <- ソート済み
print(origin_numbers) # 出力: [5, 2, 9, 1, 5, 6] <- 元の順序がキープされている
昇順(小さい順)と降順(大きい順)の制御
デフォルトの状態では、数値は小さい順、文字列はアルファベット・五十音順(Unicodeコードポイント順)の「昇順」で並び替わります。これを逆順の「降順」にしたい場合は、引数に reverse=True を指定します。
# sort() メソッドで降順ソート
numbers = [4, 7, 1, 3]
numbers.sort(reverse=True)
print(numbers) # 出力: [7, 4, 3, 1]
# sorted() 関数で降順ソート
letters = ['b', 'a', 'd', 'c']
sorted_letters = sorted(letters, reverse=True)
print(sorted_letters) # 出力: ['d', 'c', 'b', 'a']
key引数を用いた「カスタムソート」とラムダ式の実務利用
単なる大小比較ではなく、「文字列の長さ順」や「辞書データの中にある特定のキーの値」を基準にして並び替えたい場合、key 引数に基準となる関数を指定します。
実務では、その場限りのソート基準を作るために、名前のない使い捨ての関数であるラムダ式(lambda)が非常によく組み合わされます。
# 1. 組み込み関数 len を指定して、文字数が短い順にソート
words = ["banana", "apple", "cherry", "date"]
words.sort(key=len)
print(words) # 出力: ['date', 'apple', 'banana', 'cherry'] (4文字、5文字、6文字、6文字)
# 2. ラムダ式(lambda)を使い、辞書の「価格(price)」を基準にソート
products = [
{"name": "林檎", "price": 150},
{"name": "蜜柑", "price": 80},
{"name": "葡萄", "price": 300}
]
# 各要素(x)から price の値を取り出して比較基準にする
products.sort(key=lambda x: x["price"])
print(products)
# 出力: [{'name': '蜜柑', 'price': 80}, {'name': '林檎', 'price': 150}, {'name': '葡萄', 'price': 300}]
ソートアルゴリズムの特性と注意点まとめ
Pythonのソート仕様に関する、設計上の重要な知識です。
| 考慮すべきポイント | 動作仕様と詳細 | 開発時の実装指針 |
|---|---|---|
| 破壊性(副作用) | sort() は元のデータを上書き消去します。sorted() はメモリ上に新しい領域を確保します。 |
元の並び順を後続の処理で再利用したい場合や、関数の引数として受け取ったリストを書き換えたくない場合は sorted() を選択してください。 |
| メモリ効率 | sort() はリストの内部領域だけで要素を入れ替えるため、余分なメモリを使いません。 |
数万件以上の超巨大なリストを扱う場合、sorted() を使うとメモリ容量を圧迫するため、sort() によるインプレース(その場)ソートが有利です。 |
| ソートの安定性 (注釈あり) |
Pythonは「安定ソート(Stable Sort)」であるTimsortを採用しています。比較基準(key)が同じ値を持つ要素同士は、ソート前と同じ相対的な順序が100%維持されます。 | 上記の「文字数順ソートの例」で、同じ6文字の "banana" と "cherry" は、元々左側にあった "banana" がソート後も必ず左側にキープされます。順序がランダムに崩れる心配はありません。 |
| 非対応の型混在 | リストの中に「数値型」と「文字列型」が混在している状態でソートを走らせると、比較不能のため TypeError が発生します。 |
ソートを実行する前に、リスト内のデータ型が統一されているか、あるいは key 引数で同じデータ型(例: key=str)に変換して比較するよう配慮が必要です。 |
まとめ
- 「その場」か「複製」かで使い分ける: 元のデータを書き換えても構わずメモリを節約したいときは
list.sort()、元の順序を維持した安全なプログラムにしたいときはsorted(list)を選ぶという原則を徹底しましょう。 - ラムダ式による柔軟な並び替え:
key=lambda x: ...のアプローチをマスターすることで、複雑なオブジェクトのリストや、ネストされた辞書データであっても、任意の項目を軸にした精密なソートが可能になります。 - 安定ソートの性質を活かす: Pythonのソートは順序が保証される安定ソートです。これを利用して、「第1基準でソートした後に、別の第2基準で再度ソートする」といった複数条件による段階的な並び替えロジックも綺麗に実現できます。