辞書の中身を「キー順」や「値の大小」で並べ替えたい場面は多いですが、辞書そのものにはソート機能がありません。
Pythonではsorted
関数とkey
引数を使って、辞書のキー、値、項目(キーと値のペア)を柔軟に並べ替えます。
本記事では基本から実用までを丁寧に解説します。
辞書ソートの基本
Pythonの辞書と順序保持の前提
Python 3.7以降の標準のdict
は、挿入順序を保持します。
つまり、ある順序でキーと値のペア(項目)を追加すると、その順序で反復(走査)されます。
ただし「辞書自体を直接ソートする」ことはできません。
ソートはあくまで「並べ替えられた新しいリストを作る」操作であり、その結果を必要に応じて新しい辞書として構築し直します。
次の短い例で、挿入順序が保持されることを確認できます。
# 挿入順序が保持される例
d = {}
d["b"] = 2
d["a"] = 1
d["c"] = 3
for k, v in d.items():
print(k, v)
b 2
a 1
c 3
ソートはsortedで行う key引数とreverseの役割
並べ替えは組み込み関数sorted(iterable, *, key=None, reverse=False)
で行います。
sorted
はイテラブル(反復可能オブジェクト)を受け取り、新しいリストを返します。
key
: 各要素から比較用の値を取り出す関数を指定します。reverse
: 降順にしたい場合はTrue
を指定します(デフォルトは昇順)。
辞書を扱う場合、sorted
に渡す対象は次のいずれかです。
d.keys()
(または単にd
) … キーの並べ替えd.values()
… 値の並べ替えd.items()
… (キー, 値)タプルの並べ替え
key
関数の中で、どの要素を基準に並べるかを柔軟に指定できます。
keys values items どれをソートするか
用途に応じて、何をsorted
に渡すかを選びます。
基準にしたい情報がkey
だけか、value
だけか、両方かで使い分けます。
対象 | 返る型 | key関数に渡る値 | 典型用途 |
---|---|---|---|
d または d.keys() | キーのリスト | 各キー | キー名でのソート、キーを基準に2次基準を作る |
d.values() | 値のリスト | 各値 | 単に値の大小を並べたい(どのキーかは不要) |
d.items() | (キー, 値)のリスト | 各(キー, 値)タプル | キーや値を自由に基準化し、並べたペアをそのまま再構築したい |
以降の実例は、基本的にd.items()
をsorted
し、必要なら新しい辞書へ組み直す流れを示します。
キーでソートする方法
キーで昇順ソート sortedとdict.items
キーを辞書順(昇順)にしたい場合、d.items()
をそのままsorted
に渡せば、(キー, 値)タプルはまずキーで比較されるため簡単です。
# キーで昇順ソート
d = {"banana": 3, "Apple": 5, "cherry": 1}
# (キー, 値)のリストとしてソート
pairs = sorted(d.items()) # デフォルトはキー昇順
print(pairs) # 並びを確認
# 新しい辞書を並び替え順で構築
sorted_dict = dict(pairs)
print(sorted_dict)
[('Apple', 5), ('banana', 3), ('cherry', 1)]
{'Apple': 5, 'banana': 3, 'cherry': 1}
キーで降順ソート reverse=True
降順にしたいときはreverse=True
を指定します。
# キーで降順ソート
d = {"banana": 3, "Apple": 5, "cherry": 1}
sorted_dict_desc = dict(sorted(d.items(), reverse=True))
print(sorted_dict_desc)
{'cherry': 1, 'banana': 3, 'Apple': 5}
大文字小文字を無視したキーソート str.lowerをkeyに
キーの大小を無視してソートしたい場合は、キーを小文字化した値を比較基準にします。
str.lower
またはより包括的なstr.casefold
が使えます。
# 大文字小文字を無視してキーをソート
d = {"banana": 3, "Apple": 5, "cherry": 1, "apricot": 2}
# key関数で(キー, 値)タプルの0番目(キー)を小文字化して比較
pairs_ci = sorted(d.items(), key=lambda kv: kv[0].lower())
print(dict(pairs_ci))
# 国際化を考慮するなら casefold の方が厳密
pairs_ci2 = sorted(d.items(), key=lambda kv: kv[0].casefold())
print(dict(pairs_ci2))
{'Apple': 5, 'apricot': 2, 'banana': 3, 'cherry': 1}
{'Apple': 5, 'apricot': 2, 'banana': 3, 'cherry': 1}
値でソートする方法
値で昇順ソート key=lambda item[1]
値を基準にしたい場合は、(キー, 値)
タプルの1番目の要素(値)をkey
関数で返すようにします。
# 値で昇順ソート
d = {"apple": 5, "banana": 3, "cherry": 1}
pairs_by_value = sorted(d.items(), key=lambda kv: kv[1])
print(pairs_by_value)
print(dict(pairs_by_value))
[('cherry', 1), ('banana', 3), ('apple', 5)]
{'cherry': 1, 'banana': 3, 'apple': 5}
補足として、キーを値で並べたいだけならsorted(d, key=d.get)
というイディオムも便利です。
# キーを値の小さい順に並べる(結果はキーのリスト)
d = {"apple": 5, "banana": 3, "cherry": 1}
keys_by_value = sorted(d, key=d.get)
print(keys_by_value)
['cherry', 'banana', 'apple']
値で降順ソート reverse=True
降順はreverse=True
を指定するだけです。
# 値で降順ソート
d = {"apple": 5, "banana": 3, "cherry": 1}
sorted_desc = dict(sorted(d.items(), key=lambda kv: kv[1], reverse=True))
print(sorted_desc)
{'apple': 5, 'banana': 3, 'cherry': 1}
数値の絶対値でソート key=absやitemgetter
値が負数を含む場合、絶対値で並べたいケースがあります。
その場合はabs
をkey
関数に組み込みます。
operator.itemgetter
を使うと「タプルの何番目を基準にするか」を明示的に書けます。
from operator import itemgetter
# 絶対値でソートする例
d = {"pos_small": 2, "neg_large": -10, "pos_large": 8, "neg_small": -3}
# その1: ラムダで値の絶対値を返す
pairs_abs = sorted(d.items(), key=lambda kv: abs(kv[1]))
print(pairs_abs)
print(dict(pairs_abs))
# その2: itemgetterで値を取り出してからabsを適用
get_value = itemgetter(1)
pairs_abs2 = sorted(d.items(), key=lambda kv: abs(get_value(kv)))
print(dict(pairs_abs2))
[('pos_small', 2), ('neg_small', -3), ('pos_large', 8), ('neg_large', -10)]
{'pos_small': 2, 'neg_small': -3, 'pos_large': 8, 'neg_large': -10}
{'pos_small': 2, 'neg_small': -3, 'pos_large': 8, 'neg_large': -10}
並べ替え結果の扱いと注意点
並び替えた順で新しい辞書を作る dict内包表記
並び替えた結果から「その順序で走査できる新しい辞書」を作るには、dict(...)
コンストラクタか辞書内包表記を使います。
Python 3.7以降はdict
が挿入順を保持するので、並び替え順で挿入すればその順序が保たれます。
# dictコンストラクタで再構築
d = {"b": 2, "a": 1, "c": 3}
sorted_items = sorted(d.items()) # キー昇順
sorted_dict = dict(sorted_items)
print(sorted_dict)
# 辞書内包表記でも同様
sorted_dict2 = {k: v for k, v in sorted(d.items(), key=lambda kv: kv[1])} # 値昇順
print(sorted_dict2)
{'a': 1, 'b': 2, 'c': 3}
{'a': 1, 'c': 3, 'b': 2}
注: もともと辞書のキーは一意なので、items()
を経由して再構築するときに上書きが発生する心配は通常ありません。
複数条件で安定ソートする タプルkeyとitemgetter
Pythonのsorted
は安定ソートです。
複数の基準で並べたい場合、次の2通りが実用的です。
- 単一回の
sorted
で「タプルの比較キー」を返す - 複数回の
sorted
を「劣後→優先」の順に適用する(安定性を利用)
from operator import itemgetter
d = {
"alice": 3,
"bob": 10,
"anna": 10,
"carol": 2,
}
# 方法1: タプルの比較キー
# 基準: 値(降順) → キー(昇順)
pairs_multi = sorted(
d.items(),
key=lambda kv: (-kv[1], kv[0]) # 1番目に値の降順、2番目にキーの昇順
)
print(pairs_multi)
# 方法2: 安定ソートの二段適用
# まず劣後基準(キー昇順)でソートし、その結果に優先基準(値降順)を掛ける
pairs_step1 = sorted(d.items(), key=itemgetter(0)) # キー昇順
pairs_step2 = sorted(pairs_step1, key=itemgetter(1), reverse=True) # 値降順
print(pairs_step2)
[('anna', 10), ('bob', 10), ('alice', 3), ('carol', 2)]
[('anna', 10), ('bob', 10), ('alice', 3), ('carol', 2)]
sortedとlist.sortの違い 辞書を直接はソートできない
sorted(iterable, ...)
は新しいリストを返す関数で、あらゆるイテラブルに使えます。
辞書そのものはイテラブルですが、反復するとキーが得られるため、sorted(d)
は「キーを並べたリスト」を返します。
それに対して、list.sort(...)
はリストに対する破壊的(インプレース)メソッドで、戻り値はNone
です。
辞書にはsort
メソッドがありません。辞書を並べ替えたい場合は、d.keys()
やd.items()
などのビューをsorted
して、その結果を必要なら辞書へ組み直します。
d = {"b": 2, "a": 1, "c": 3}
# sorted(d) はキーを並べ替える
print(sorted(d)) # ['a', 'b', 'c']
# items()をsortedして(キー, 値)の並んだリストにする
print(sorted(d.items())) # [('a', 1), ('b', 2), ('c', 3)]
# list.sortはリスト専用で戻り値None
pairs = list(d.items())
print(pairs.sort() is None) # True
print(pairs) # インプレースでソート済み
['a', 'b', 'c']
[('a', 1), ('b', 2), ('c', 3)]
True
[('a', 1), ('b', 2), ('c', 3)]
まとめ
辞書は挿入順を保持しますが、辞書自体を直接ソートすることはできません。
並べ替えはsorted
を使い、対象にd
(キー)、d.values()
(値)、d.items()
(項目)のいずれを渡すかを選び、key
引数で比較基準を設計します。
キー基準ならsorted(d.items())
、値基準ならkey=lambda kv: kv[1]
やitemgetter(1)
、絶対値や大文字小文字無視などのカスタム要件にも柔軟に対応できます。
結果を辞書として利用したい場合は、その順で再構築すれば挿入順が反映されます。
安定ソートを活かした複数基準の並べ替えや、reverse=True
による降順指定も含め、基本パターンを押さえておけば実務の大半をシンプルに解決できます。