※このブログではサーバー運用、技術の検証等の費用のため広告をいれています。
記事が見づらいなどの問題がありましたらContactからお知らせください。


【Python3】dict型の配列をsortに渡すhookで柔軟に並び替えする方法

python3 lambda dict 無名関数 list hook

投稿日:2020年10月24日

このエントリーをはてなブックマークに追加
Pythonでdict型の配列を並び替えをする場合、sort()関数やsorted()関数をそのまま使うことはできません。この記事ではdict型の配列の並び変えの仕方について実践を交えて細かく解説しています。

はじめに

この記事について

Pythonでdict型の配列を並び替えをする場合、sort()関数sorted()関数をそのまま使うことはできません。この記事ではdict型の配列の並び変えの仕方について実践を交えて細かく解説しています。

環境

この記事のコードは以下の環境で実行されました。

  • Python==3.6.3

実践

ここではサンプルとして以下のdict型の配列について考えます。

data = [
    {
        "name" : "藍染 惣右介",
        "sex" : "male",
        "height" : 205,
        "weight" : 91
    },
    {
        "name" : "更木 剣八",
        "sex" : "male",
        "height" : 202,
        "weight" : 90
    },
    {
        "name" : "四楓院 夜一",
        "sex" : "female",
        "height" : 156,
        "weight" : 42
    },
    {
        "name" : "日番谷 冬獅郎",
        "sex" : "male",
        "height" : 133,
        "weight" : 28
    },
    {
        "name" : "雛森 桃",
        "sex" : "female",
        "height" : 151,
        "weight" : 39
    },
]

sort()関数とsorted()関数

list型にはsort()という順番を並びかえるメソッドが用意されているのですが、
これはデフォルトでは単純な大小を比較するため、
そのままではdict型の配列を処理することはできません。

data.sort()
出力
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-7-cfdd66cfdfb7> in <module>
----> 1 data.sort()

TypeError: '<' not supported between instances of 'dict' and 'dict'

この点はsorted()についても同様のことが言えます。

sorted(data)
出力
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-10-33bae22008f5> in <module>
----> 1 sorted(data)

TypeError: '<' not supported between instances of 'dict' and 'dict'

lambdaをhookでわたす

Pythonでは関数を引数に渡すことができます。

ここでは無名関数を使ってsort()関数heigtの値ごとに並び替える関数にカスタマイズしてみます。

この様に関数の引数として関数を渡すことで、その関数の処理をカスタマイズする仕組みのことをフック(hook)と言います。

data.sort(key=lambda x: x["height"])
print(data)
ターミナル
[{'name': '日番谷 冬獅郎', 'sex': 'male', 'height': 133, 'weight': 28}, {'name': '雛森 桃', 'sex': 'female', 'height': 151, 'weight': 39}, {'name': '四楓院 夜一', 'sex': 'female', 'height': 156, 'weight': 42}, {'name': '更木 剣八', 'sex': 'male', 'height': 202, 'weight': 90}, {'name': '藍染 惣右介', 'sex': 'male', 'height': 205, 'weight': 91}]

hookはsorted()でも同じように渡すことができます。

関数をhookで渡す

少し複雑な処理などを入れたい場合などには、関数を定義してそれをhookとして渡してあげると良いでしょう。

def bmi_hook(obj):
    return obj["weight"]/(obj["height"] ^ 2)

data.sort(key=bmi_hook)

print(data)
出力
[{'name': '日番谷 冬獅郎', 'sex': 'male', 'height': 133, 'weight': 28}, {'name': '雛森 桃', 'sex': 'female', 'height': 151, 'weight': 39}, {'name': '四楓院 夜一', 'sex': 'female', 'height': 156, 'weight': 42}, {'name': '藍染 惣右介', 'sex': 'male', 'height': 205, 'weight': 91}, {'name': '更木 剣八', 'sex': 'male', 'height': 202, 'weight': 90}]

昇順・降順

昇順・降順はhookが返す値をマイナスにする方法などもありますが、

reverse引数によっても制御することができます。

data.sort(key=lambda x: x["height"],reverse=False)
print(data)  #昇順

data.sort(key=lambda x: x["height"],reverse=True)
print(data)  #降順
出力
[{'name': '日番谷 冬獅郎', 'sex': 'male', 'height': 133, 'weight': 28}, {'name': '雛森 桃', 'sex': 'female', 'height': 151, 'weight': 39}, {'name': '四楓院 夜一', 'sex': 'female', 'height': 156, 'weight': 42}, {'name': '更木 剣八', 'sex': 'male', 'height': 202, 'weight': 90}, {'name': '藍染 惣右介', 'sex': 'male', 'height': 205, 'weight': 91}]
[{'name': '藍染 惣右介', 'sex': 'male', 'height': 205, 'weight': 91}, {'name': '更木 剣八', 'sex': 'male', 'height': 202, 'weight': 90}, {'name': '四楓院 夜一', 'sex': 'female', 'height': 156, 'weight': 42}, {'name': '雛森 桃', 'sex': 'female', 'height': 151, 'weight': 39}, {'name': '日番谷 冬獅郎', 'sex': 'male', 'height': 133, 'weight': 28}]

参考書籍

このエントリーをはてなブックマークに追加


関連記事

記事へのコメント
2:名無しさん
2022年11月27日13:24