辞書のデータは順序が保証されないと思われがちですが、Python 3.7以降では挿入順序が保持されます。
その一方で、分析や表示のためにキーや値の大小で並べ替えたい場面は多くあります。
本記事では辞書のソートをsorted関数とkey引数で実現する基本から、キーまたは値での実践的な並べ替え、結果の活用までを、初心者向けに段階を踏んで解説します。
辞書のソートの基本(sortedとkey引数)
何を並べ替えるか(keys/values/items)
辞書は「キーと値の対応」を持つコレクションです。
並べ替えたい対象は大きく3つに分けられます。
どれを並べ替えるかで書き方が変わるため、まずは対象をはっきりさせます。
- キーの一覧(例: アルファベット順にキーを見たい)
- 値の一覧(例: 小さい値から並べたい)
- キーと値の組(例: 値で並べ替えてからペアで扱いたい)
以下の表は、典型的に扱う対象と、sortedで並べ替えるときの入力例をまとめたものです。
| 並べ替える対象 | 入力に使うオブジェクト | 返る要素の形 | 典型的用途 |
|---|---|---|---|
| キー | d.keys() または d | キー | 見出しの順序を整える |
| 値 | d.values() | 値 | 値だけ並べたいとき |
| キーと値の組 | d.items() | (key, value)のタプル | 並べ替え後に辞書へ戻す |
実務ではd.items()を並べ替え、必要なら戻して使うのが最も応用が利きます。
sortedはリストを返す
sortedは常に新しい「リスト」を返します。
元の辞書を直接並べ替えることはありません。
# 基本の挙動: sortedは常に新しいリストを返す
d = {"b": 2, "a": 1, "c": 3}
print(sorted(d)) # キーの並び(リスト)
print(sorted(d.keys())) # 同じくキーの並び
print(sorted(d.items())) # (キー, 値)の並び(リスト)
['a', 'b', 'c']
['a', 'b', 'c']
[('a', 1), ('b', 2), ('c', 3)]
昇順/降順(reverse=True)
デフォルトは昇順です。
降順にしたい場合はreverse=Trueを指定します。
d = {"b": 2, "a": 1, "c": 3}
print(sorted(d, reverse=True)) # キーを降順
print(sorted(d.items(), reverse=True)) # (キー, 値)のペアをキー降順
['c', 'b', 'a']
[('c', 3), ('b', 2), ('a', 1)]
key引数で並べ替え基準を指定
key引数には「要素から並べ替えの基準値を取り出す関数」を渡します。
ソートの柔軟性はkey関数が握っています。
# 例: キーの長さで並べる
d = {"banana": 3, "fig": 6, "apple": 1}
# items()を並べ替えるので、要素は(key, value)のタプル
# kv[0]がキー、kv[1]が値
sorted_by_keylen = sorted(d.items(), key=lambda kv: len(kv[0]))
print(sorted_by_keylen)
[('fig', 6), ('apple', 1), ('banana', 3)]
キーでソートする
キー昇順でソート(sorted(d.items))
キーで並べ替えて、(キー, 値)の並びを得ます。
辞書へ戻す前提ならd.items()を並べ替えるのが便利です。
d = {"banana": 3, "Apple": 4, "cherry": 2}
# デフォルトはキーの辞書式順(Unicode順)で昇順
sorted_items = sorted(d.items())
print(sorted_items)
[('Apple', 4), ('banana', 3), ('cherry', 2)]
キー降順でソート(reverse=True)
降順にしたい場合はreverse=Trueを付けます。
d = {"banana": 3, "Apple": 4, "cherry": 2}
sorted_items_desc = sorted(d.items(), reverse=True)
print(sorted_items_desc)
[('cherry', 2), ('banana', 3), ('Apple', 4)]
文字列キーを大文字小文字無視でソート(str.lower)
人間にとって自然な順序にするには、大文字小文字を無視して比較します。
key=lambda kv: kv[0].lower()のように、キーを小文字化したものを基準にします。
d = {"banana": 3, "Apple": 4, "cherry": 2}
# キーを小文字化して比較することで、大文字小文字を無視
case_insensitive = sorted(d.items(), key=lambda kv: kv[0].lower())
print(case_insensitive)
[('Apple', 4), ('banana', 3), ('cherry', 2)]
より読みやすく書くなら、基準関数を定義しても良いです。
def key_lower(kv):
# kvは(キー, 値)
return kv[0].lower()
print(sorted(d.items(), key=key_lower))
[('Apple', 4), ('banana', 3), ('cherry', 2)]
数値キー/文字列キーの型混在に注意
Python 3では異なる型どうしは大小比較できません。
キーに数値と文字列が混在していると、デフォルト比較はTypeErrorになります。
# 数値キーと文字列キーが混在
d = {10: "ten", "2": "two"}
try:
print(sorted(d)) # キーを比較するのでTypeError
except TypeError as e:
print("TypeError:", e)
# 対策: すべて文字列化して比較する
print(sorted(d, key=str)) # ['10', '2']の文字列比較に相当
print(sorted(d.items(), key=lambda kv: str(kv[0])))
TypeError: '<' not supported between instances of 'str' and 'int'
['10', '2']
[(10, 'ten'), ('2', 'two')]
混在させないのが最善ですが、やむを得ない場合はkey=strなどで正規化します。
値でソートする
値昇順でソート(key=lambda kv: kv[1])
値でソートするにはd.items()を並べ替え、基準として「値」を取り出します。
d = {"banana": 3, "apple": 4, "cherry": 2}
# 値(kv[1])を基準に昇順
by_value_asc = sorted(d.items(), key=lambda kv: kv[1])
print(by_value_asc)
[('cherry', 2), ('banana', 3), ('apple', 4)]
値降順でソート(reverse=True)
降順にする場合はreverse=Trueを追加します。
d = {"banana": 3, "apple": 4, "cherry": 2}
by_value_desc = sorted(d.items(), key=lambda kv: kv[1], reverse=True)
print(by_value_desc)
[('apple', 4), ('banana', 3), ('cherry', 2)]
operator.itemgetter(1)で簡潔に書く
lambda kv: kv[1]はoperator.itemgetter(1)で簡潔かつ高速に書けます。
頻繁に使う形なので覚えておくと便利です。
from operator import itemgetter
d = {"banana": 3, "apple": 4, "cherry": 2}
print(sorted(d.items(), key=itemgetter(1))) # 値で昇順
print(sorted(d.items(), key=itemgetter(1), reverse=True)) # 値で降順
[('cherry', 2), ('banana', 3), ('apple', 4)]
[('apple', 4), ('banana', 3), ('cherry', 2)]
値が同じ場合はキーで第二ソート(安定ソートの活用)
Pythonのソートは安定です。
同じ値どうしの相対順を保ちます。
これを利用して、値が同じときにキーで順序付けできます。
方法1: タプルを返すkeyで一次・二次の基準を同時に指定します。
d = {"b": 2, "c": 1, "a": 2, "d": 1}
# (値, キー)の順で昇順 → 値が同じならキーで比較
sorted_two_keys = sorted(d.items(), key=lambda kv: (kv[1], kv[0]))
print(sorted_two_keys)
[('c', 1), ('d', 1), ('a', 2), ('b', 2)]
方法2: 安定ソートを2回使います。
まずキーで並べ、その結果を値で並べます。
d = {"b": 2, "c": 1, "a": 2, "d": 1}
# 先にキーで昇順
stage1 = sorted(d.items(), key=lambda kv: kv[0])
# 次に値で昇順(安定なので、同値の中ではstage1の順=キー昇順が維持)
stage2 = sorted(stage1, key=lambda kv: kv[1])
print(stage2)
[('c', 1), ('d', 1), ('a', 2), ('b', 2)]
並べ替え結果の使い方と注意点
dictへ戻して順序を保持(Python 3.7+)
Python 3.7以降の通常の辞書は挿入順序を保持します。
並べ替えたitemsから辞書を作ると、その順序で走査できます。
d = {"banana": 3, "apple": 4, "cherry": 2}
# 値で昇順に並べ替え
sorted_items = sorted(d.items(), key=lambda kv: kv[1])
# 並び順のままdictへ戻す
sorted_dict = dict(sorted_items)
print(sorted_dict) # 表示上は通常のdict
print(list(sorted_dict.items())) # 順序が保持されているか確認
{'cherry': 2, 'banana': 3, 'apple': 4}
[('cherry', 2), ('banana', 3), ('apple', 4)]
OrderedDictは必要なときのみ
順序保持だけが目的なら通常のdictで十分です。
collections.OrderedDictは、move_to_endなど順序操作の追加APIが必要な場合に限り使います。
from collections import OrderedDict
d = {"b": 2, "a": 1, "c": 3}
od = OrderedDict(sorted(d.items())) # 生成時に順序を固定
print(list(od.items()))
# 特有のAPI: 'a'を末尾へ移動
od.move_to_end("a")
print(list(od.items()))
[('a', 1), ('b', 2), ('c', 3)]
[('b', 2), ('c', 3), ('a', 1)]
sorted(d)はキーのみをソートする点に注意
sorted(d)はキーの並び(リスト)だけを返します。
キーと値のペアを並べたい場合はsorted(d.items())を使います。
d = {"b": 2, "a": 1}
print(sorted(d)) # キーだけ
print(sorted(d.items())) # (キー, 値)のペア
['a', 'b']
[('a', 1), ('b', 2)]
d.sort()は存在しない
リストにはlist.sort()がありますが、辞書にはd.sort()はありません。
辞書を並べ替えるときはsortedを使うのが原則です。
d = {"b": 2, "a": 1}
try:
d.sort() # dictにsortは無い
except AttributeError as e:
print("AttributeError:", e)
AttributeError: 'dict' object has no attribute 'sort'
パフォーマンスとkey関数のコスト
ソート自体は要素数をnとして概ねO(n log n)です。
実務ではkey関数のコストが支配的になりやすいため、以下を意識します。
基準値の計算が重い場合は、keyで毎回計算せず前処理して辞書に持たせる、またはoperator.itemgetterのような高速な取り出しを使います。
上位k件だけ必要なら全件ソートせずheapq.nsmallestやheapq.nlargestを検討します。
# itemgetterはlambdaより速いことが多い
from operator import itemgetter
d = {f"k{i}": i % 5 for i in range(10_000)}
# 値でソート(高速な取り出し)
sorted_fast = sorted(d.items(), key=itemgetter(1))
print(len(sorted_fast), "items sorted")
10000 items sorted
まとめ
本記事では、Pythonの辞書をsortedとkey引数で柔軟にソートする方法を、キー/値/ペアのいずれを対象にするかという視点から体系的に解説しました。
キーの昇降順、大小文字無視、値での昇降順、安定ソートによる第2基準、そして並べ替え結果を辞書へ戻して順序を活かす実践法まで扱いました。
Python 3.7以降は通常の辞書が挿入順を保持するため、まずはsorted(d.items())で並べ替え、必要に応じてdictへ戻すのが定石です。
型の混在やsorted(d)がキーだけを返す点、d.sort()が存在しない点に注意しつつ、基準値の設計とkeyのコストを意識すると、確実で速いソートが実現できます。
