閉じる

もう迷わない!Pythonでリストを昇順・降順にソートする

Pythonでリストの順序を整える場面は、数値の集計結果を並べたり、文字列の一覧を見やすくしたりと日常的にあります。

本記事では、昇順・降順の基本から、reverseやkeyによる柔軟な並べ替え、初心者がつまずきやすい注意点、効率よく書くコツまで順を追って丁寧に解説します。

リストを昇順・降順にソートする基本

sortメソッドとsorted関数の違い

リストの並べ替えには、インスタンスメソッドのlist.sort()と組み込み関数のsorted()の2通りがあります。

まずは両者の性質を押さえておくと、その後の選択が迷いにくくなります。

ざっくり比較表

項目list.sort()sorted()
呼び出し方my_list.sort(...)sorted(iterable, ...)
破壊的かはい(元のリストを書き換える)いいえ(新しいリストを返す)
戻り値Noneソート済みの新しいリスト
対象リストのみ任意の反復可能オブジェクト(リスト、タプル、集合、ジェネレータなど)
メモリ使用少なめ(原則インプレース)追加メモリが必要
主な用途大きなリストを効率よく並べ替える元のデータを残したい、一時的に並べ替えたい

動作の違いをコードで確認

sort()は戻り値がNoneである点に注意します。

一方sorted()は新しいリストを返し、元のリストは変化しません。

Python
# sort() と sorted() の違いを確認するサンプル

nums = [3, 1, 2]

# インプレースに並べ替え(元のリストが書き換わる)
result_in_place = nums.sort()
print("nums after sort():", nums)              # 並び替え済み
print("return value of sort():", result_in_place)  # None に注意

# 新しいリストを受け取る(sortedは元のリストを変更しない)
nums2 = [3, 1, 2]
result_new = sorted(nums2)
print("nums2 after sorted():", nums2)          # 変更なし
print("result of sorted():", result_new)       # 並び替え済みの新しいリスト
実行結果
nums after sort(): [1, 2, 3]
return value of sort(): None
nums2 after sorted(): [3, 1, 2]
result of sorted(): [1, 2, 3]

昇順にソートする書き方

昇順(小さい順)は最も基本的な並べ替えです。

デフォルト設定のままで実現できます。

list.sort()で昇順

Python
# 昇順にソート(インプレース)

numbers = [5, 1, 9, 3, 3]
numbers.sort()   # デフォルトは昇順
print(numbers)
実行結果
[1, 3, 3, 5, 9]

sorted()で昇順

Python
# 昇順にソート(新しいリストを受け取る)

numbers = [5, 1, 9, 3, 3]
sorted_numbers = sorted(numbers)
print("original:", numbers)
print("sorted  :", sorted_numbers)
実行結果
original: [5, 1, 9, 3, 3]
sorted  : [1, 3, 3, 5, 9]

降順にソートする書き方

降順(大きい順)はreverse=Trueを指定します。

Python
# 降順にソートする2通り

arr1 = [5, 1, 9, 3]
desc1 = sorted(arr1, reverse=True)  # 新しいリスト
print(desc1)

arr2 = [5, 1, 9, 3]
arr2.sort(reverse=True)             # インプレース
print(arr2)
実行結果
[9, 5, 3, 1]
[9, 5, 3, 1]

補足として、数値であればkey=lambda x: -xのように負号を使う方法もありますが、reverse=Trueのほうが意図が明確で、NaNなどの特殊値や非数値の並べ替えでは安全性が高いです。

reverseとkeyで柔軟にソート

reverse=Trueで降順にする

reverse=Trueは「降順に並べ替える」ための引数です。

よく混同されるlist.reverse()は「現在の並び順を単純にひっくり返す」だけで、値の大小には基づきません。

両者は用途が異なります。

Python
# reverse=True と list.reverse() の違い

a = [3, 1, 2]
a.reverse()  # 元の順序を単に反転
print("list.reverse() ->", a)  # [2, 1, 3] (降順ではない)

b = [3, 1, 2]
b.sort(reverse=True)  # 大小に基づき降順に並べ替え
print("sort(reverse=True) ->", b)  # [3, 2, 1]
実行結果
list.reverse() -> [2, 1, 3]
sort(reverse=True) -> [3, 2, 1]

keyで並べ替え基準を指定

key引数に「各要素から比較用の値を取り出す関数」を渡すと、柔軟に並べ替え基準を指定できます。

key関数は各要素に1回ずつ呼ばれ、その戻り値に基づいて整列されます。

文字列を長さで並べ替える

Python
# 文字列の長さで昇順にソート

words = ["banana", "kiwi", "apple", "fig"]
by_length = sorted(words, key=len)  # len をそのまま key に使える
print(by_length)
実行結果
['fig', 'kiwi', 'apple', 'banana']

タプルの2番目→3番目の値で並べ替える

Python
# (名前, 身長, 体重) のタプルを、身長→体重の順に昇順ソート

students = [
    ("A", 180, 70),
    ("B", 170, 80),
    ("C", 180, 65),
]
ordered = sorted(students, key=lambda x: (x[1], x[2]))
print(ordered)
実行結果
[('B', 170, 80), ('C', 180, 65), ('A', 180, 70)]

辞書の特定キーで並べ替える

Python
# リスト内の辞書を、年齢→名前の順で昇順に並べ替え

users = [
    {"name": "alice", "age": 30},
    {"name": "bob", "age": 25},
    {"name": "carol", "age": 30},
]
ordered = sorted(users, key=lambda u: (u["age"], u["name"]))
print(ordered)
実行結果
[{'name': 'bob', 'age': 25}, {'name': 'alice', 'age': 30}, {'name': 'carol', 'age': 30}]

文字列を大文字小文字無視でソート

大文字小文字を区別せずにソートしたいときはkey=str.lowerが簡単です。

より国際化に配慮するならstr.casefoldが推奨です。

Python
# 大文字小文字を無視してソートする例

names = ["bob", "Alice", "carol", "ALAN", "apple", "Apple", "APPLE"]

print("default :", sorted(names))                    # デフォルト(大文字が先)
print("lower   :", sorted(names, key=str.lower))     # 大小無視
print("casefold:", sorted(names, key=str.casefold))  # より厳密な大小無視

# 同じキー(例: 'apple')同士は元の順序が保たれる(安定ソート)
pair = ["apple", "Apple", "APPLE"]
print("stable  :", sorted(pair, key=str.lower))
実行結果
default : ['ALAN', 'APPLE', 'Alice', 'Apple', 'apple', 'bob', 'carol]
lower   : ['ALAN', 'Alice', 'apple', 'Apple', 'APPLE', 'bob', 'carol']
casefold: ['ALAN', 'Alice', 'apple', 'Apple', 'APPLE', 'bob', 'carol']
stable  : ['apple', 'Apple', 'APPLE']

初心者がつまずくポイント

元のリストを残したいならsorted

list.sort()は元のリストを直接書き換えるため、後で元の順序を使いたい場合に困ります。

そういうときはsorted()を使って新しいリストを受け取ります。

コピーしてからsort()でも構いません。

Python
# 元のリストを残したい場合の2通り

data = [7, 2, 5]

# 1) sorted() を使う
sorted_data = sorted(data)
print("data       :", data)
print("sorted_data:", sorted_data)

# 2) コピーしてから sort()
copy_data = data[:]  # あるいは list(data) や data.copy()
copy_data.sort()
print("copy_data  :", copy_data)
実行結果
data       : [7, 2, 5]
sorted_data: [2, 5, 7]
copy_data  : [2, 5, 7]

なお、sorted_list = my_list.sort()としてしまうとsorted_listNoneになってしまいます。

この書き方は避けましょう。

型が混在するリストはソートできない

Python 3では、数値と文字列のように比較不可能な型が混在しているとTypeErrorになります。

対策は「型をそろえる」か「keyで比較用の同型値を作る」ことです。

Python
# 型が混在しているとエラーになる例
mixed = [1, "2", 3]
try:
    print(sorted(mixed))
except TypeError as e:
    print("TypeError:", e)

# 対策1: すべて数値に変換(文字列が数値として解釈できる前提)
numeric_sorted = sorted(int(x) for x in mixed)
print("numeric_sorted:", numeric_sorted)

# 対策2: keyで同じ型に正規化して比較(ここでは文字列化)
mixed2 = [10, "2", 3, "11"]
as_string_sorted = sorted(mixed2, key=lambda x: str(x))
print("as_string_sorted:", as_string_sorted)

# Noneが混じる場合は「Noneを最後に送る」キーにする
with_none = [3, None, 1, None]
none_last = sorted(with_none, key=lambda x: (x is None, x))
print("none_last:", none_last)
実行結果
TypeError: '<' not supported between instances of 'str' and 'int'
numeric_sorted: [1, 2, 3]
as_string_sorted: [10, 11, 2, 3]
none_last: [1, 3, None, None]

上の「Noneを最後に送る」テクニックは、キーをタプル(x is None, x)にすることで、最初の要素(False/True)で「Noneかどうか」を判定し、Trueを持つ要素(=None)が後ろに回る仕組みです。

両方がNoneのときのみ2番目の値xが比較されますが、同じNone同士なので問題になりません。

安定ソートで同一キーの順序維持

Pythonのソートは安定ソートです。

これは「比較キーが同じ要素同士は元の相対順を維持する」という性質を意味します。

複数条件で整列するときにとても役立ちます。

Python
# 2番目の値(グループ)でソート。グループ内の元の順序は維持される。

records = [
    ("A", 2),
    ("B", 1),
    ("C", 1),
    ("D", 3),
]
ordered = sorted(records, key=lambda x: x[1])
print(ordered)  # ('B', 1) と ('C', 1) の順序は元のまま
実行結果
[('B', 1), ('C', 1), ('A', 2), ('D', 3)]

Pythonリストソートのベストプラクティス

大きなリストを効率よくソート

Pythonのソート実装はTimsortと呼ばれるアルゴリズムで、平均・最悪計算量はおおむねO(n log n)です。

ほぼ整列済みのデータでは非常に高速に動作します。

大きなリストでは、以下の点に気を付けると効率的です。

  • 元のリストを破壊して構わないならlist.sort()を使い、追加メモリ消費を抑えます。
  • 高価な変換を伴う基準で並べ替えるなら、keyで一度だけ計算させます(Pythonのソートは「キーを各要素1回だけ」計算してから並べ替えます)。
  • 上位N件だけ欲しい場合は、全部をソートせずheapq.nlargestheapq.nsmallestを使います。
Python
# key関数は各要素に1回だけ呼ばれる(重い処理ならここで済む)

counter = {"n": 0}
def key_func(x):
    counter["n"] += 1
    return x % 10  # 例: 下1桁で並べ替える

data = list(range(20, 0, -1))  # 20..1
_ = sorted(data, key=key_func)
print("key called:", counter["n"], "times")
実行結果
key called: 20 times
Python
# 全件ソートせずに上位N件を求める

import heapq

data = [5, 1, 9, 3, 7, 4]
top3 = heapq.nlargest(3, data)   # 大きい順に3件
low3 = heapq.nsmallest(3, data)  # 小さい順に3件
print("top3:", top3)
print("low3:", low3)
実行結果
top3: [9, 7, 5]
low3: [1, 3, 4]

可読性が高い書き方のコツ

読みやすさを意識したkeyの書き方は、後から見返したときの理解速度に直結します。

短いlambdaで済む場合はそれで良いですが、条件が増えるなら関数名を付けたキー関数に切り出すと意図が伝わりやすくなります。

Python
# 長さ→アルファベット順(大小無視)の順に並べる、という意図を関数名に込める

def by_len_then_alpha(s: str):
    return (len(s), s.lower())

words = ["pear", "fig", "banana", "Apple", "apricot"]
print(sorted(words, key=by_len_then_alpha))
実行結果
['fig', 'pear', 'Apple', 'banana', 'apricot']

辞書やタプルの特定要素で並べ替えるなら、operatorモジュールのitemgetter/attrgetterが簡潔で意図が明快です。

Python
# itemgetterで辞書のキーを指定して並べ替える

from operator import itemgetter

users = [
    {"name": "Alice", "age": 30},
    {"name": "Bob",   "age": 25},
    {"name": "Carol", "age": 25},
]
print(sorted(users, key=itemgetter("age", "name")))
実行結果
[{'name': 'Bob', 'age': 25}, {'name': 'Carol', 'age': 25}, {'name': 'Alice', 'age': 30}]

また、「降順にしたいからキーに負号を付ける」といったトリックは避け、reverse=Trueを使うと読み手に優しいコードになります。

複数条件のソートは、タプルキー(第1条件, 第2条件, ...)にまとめると1回で済み、保守も容易です。

sortとsortedの使い分けまとめ

使い分けの基準をまとめると次のようになります。

  • 元のリストを書き換えて良い、追加メモリを抑えたい、大量データで効率を重視: list.sort()
  • 元の順序を残したい、イテラブルをソートして新しいリストが欲しい、一時的に並べ替えたい: sorted()
  • 降順はreverse=True、基準変更はkey=...を基本形として覚える

まとめ

Pythonのリストソートは、list.sort()sorted()の違いを理解し、reversekeyを組み合わせて使いこなすだけで、非常に幅広い要件に対応できます。

基本の昇順・降順から始め、文字列の大小無視、複数条件の並べ替え、Noneや型の混在への対処などを段階的に押さえておくと、実務での困りごとを確実に解決できます。

大きなリストではインプレースなsort()heapqの活用で効率に配慮し、可読性の高いkeyの書き方を心がけることで、保守しやすいコードへとつながります。

慣れてくれば、ソートは「迷わず書ける定番テクニック」になりますので、ぜひ手を動かして身につけていきましょう。

この記事を書いた人
エーテリア編集部
エーテリア編集部

人気のPythonを初めて学ぶ方向けに、文法の基本から小さな自動化まで、実際に手を動かして理解できる記事を書いています。

クラウドSSLサイトシールは安心の証です。

URLをコピーしました!