先日とある目的で、配列を要素に持つ配列を、各配列の3番目の値を使ってソートするコードが必要になりました。
最初はそのキーになる要素だけ取り出して、 argsortしてどうにか並べ替えようとしたのですが、実はkeyって引数を使えば綺麗に実装できることがわかりました。
ドキュメントは組み込み型のlistのsortメソッドの部分が該当します。
key って引数に 単一の引数を取る関数を渡せば、listの各要素にその関数が適用され、戻り値によってソートされる様です。
なので、配列の配列を3番目の要素でソートするには、lambda 式あたりでそう言う関数を作ってあげれば実現できます。
(インデックスは0始まりなので、実際にはインデックス2を取得します。)
# ソートされるデータ作成
list_0 = [
[9, 8, 5],
[0, 8, 3],
[1, 6, 5],
[9, 0, 0],
[4, 9, 3],
[1, 4, 8],
[4, 0, 6],
[0, 3, 5],
[1, 3, 1],
[5, 2, 7],
]
# 3番目(index 2)の要素でソート
list_0.sort(key=lambda x: x[2])
print(list_0)
# [[9, 0, 0], [1, 3, 1], [0, 8, 3], [4, 9, 3], [9, 8, 5], [1, 6, 5], [0, 3, 5], [4, 0, 6], [5, 2, 7], [1, 4, 8]]
これを応用すれば、辞書の配列を特定のkeyに対応する値でソートするといったことも簡単にできます。
(lambda式に辞書オブジェクトのgetメソッド渡すだけですね。)
もちろん、lambda 式以外にも事前に定義した関数を渡すこともできます。
次の例は、トランプのカード (2〜9とTJQKAで表したランクと、cdhsで表したスートの2文字で表したもの)を強い順にソートするものです。
# カードの強さを返す関数
def card_rank(card):
rank_dict = {
"T": 10,
"J": 11,
"Q": 12,
"K": 13,
"A": 14,
}
suit_dict = {
"s": 3,
"h": 2,
"d": 1,
"c": 0,
}
return int(rank_dict.get(card[0], card[0]))*4 + suit_dict[card[1]]
card_list = ["Ks", "7d", "Ah", "3c", "2s", "Td", "Kc"]
# ソート前の並び
print(card_list)
# ['Ks', '7d', 'Ah', '3c', '2s', 'Td', 'Kc']
# 強い順にソート
card_list.sort(key=card_rank, reverse=True)
print(card_list)
# ['Ah', 'Ks', 'Kc', 'Td', '7d', '3c', '2s']
reverse = True を指定しているのはソートを降順にするためです。
このほかにも str.lower
を使って、アルファベットを小文字に統一してソートするなど、
使い方は色々ありそうです。