データの抽出・変換・並べ替え
四人のレコードから対象者を抽出し、点数と名前で並べ替えます。元の一覧、並べ替え後の一覧、各レコードの共有関係を確認し、値を変更した後に順序を更新します。
説明
一覧の加工では、要素を除外する処理と、値を別の形へ変換する処理を分けます。並べ替えは比較用のキーを指定でき、同じキーの要素は元の順序を保ちます。
四人のレコードから対象者を抽出し、点数と名前で並べ替えます。元の一覧、並べ替え後の一覧、各レコードの共有関係を確認し、値を変更した後に順序を更新します。
1同点を含む元データ
MeiとAyaは同点80で、元の順序はMeiが先です。Kenは対象外のactive=Falseにします。
rows = [{"name":"Mei","score":80,"active":True}, {"name":"Ken","score":95,"active":False}, {"name":"Aya","score":80,"active":True}, {"name":"Jun","score":70,"active":True}]名前・点数・対象フラグ; print([(r["name"],r["score"],r["active"]) for r in rows])元の順序を表示入力順と同点の位置を残したまま加工します。後で同点の順序が変わったか比較する基準になります。
2対象者だけを抽出する
forの後のifで、activeが真のレコードだけを残します。
active = [r for r in rows if r["active"]]条件に合うレコードだけ保持; print([r["name"] for r in active], len(rows), len(active))氏名と件数Mei、Aya、Junの三人です。rows自体は四件のままで、activeは新しい外側のリストです。中の辞書rはコピーせず、そのまま参照しています。
3除外せず値だけを変える
対象外は0点とする表示用の一覧を作ります。if/elseを先頭の式に置きます。
display = [(r["name"], r["score"] if r["active"] else 0要素を残して値を選択) for r in rows全レコードを対象]; print(display)変換した一覧四件を保ったままKenの表示点だけ0になります。後ろのifで要素を除外する処理とは違います。元の辞書のscoreは変更していません。
4点数だけで並べ替える
対象者を点数の高い順に並べます。sortedは新しいリストを返します。
ranked = sorted(active, key=lambda r: r["score"], reverse=True)点数をキーに降順; print([(r["name"], r["score"]) for r in ranked])同点の順序; print([r["name"] for r in rows])元の順序同点80のMeiとAyaは元の順序を保ちます。reverse=Trueでも同点の安定性は維持されます。元のrowsの順番は変わりません。
5同点なら名前の順にする
点数は降順、同点は名前の昇順というキーを組にして指定します。
named_rank = sorted(active, key=lambda r: (-r["score"], r["name"])点数降順・名前昇順); print([(r["name"], r["score"]) for r in named_rank])同点の順序を明示Aya、Mei、Junになりました。タプルの第一要素で比較し、等しければ第二要素へ進みます。点数に負号を付けて降順にし、名前は通常の昇順にしています。
6sortの戻り値と元リスト
active自身を点数順へ並べ替え、戻り値も受け取ります。
returned = active.sort(key=lambda r: r["score"], reverse=True)同じリストを並べ替える; print(returned, [r["name"] for r in active])戻り値と更新後戻り値はNoneで、activeの並びが更新されます。sortedのように新しいリストが返ると思ってactive = active.sort(...)と書くと、名前がNoneを指す結果になります。
7要素の値を変えても自動では再整列されない
activeの先頭Meiの点数を0へ変更します。元のrowsと、以前作ったrankedも表示します。
active[0]["score"] = 0共有する辞書を更新; print([(r["name"],r["score"]) for r in active])順序はそのまま; print([(r["name"],r["score"]) for r in rows])元データにも見える変更; print([(r["name"],r["score"]) for r in ranked])以前の結果にも共有された値同じ辞書を共有する各一覧からMeiの0点が見えます。ただしMeiは先頭に残り、点数順は自動更新されません。外側の一覧を新しく作ることと、レコードの複製は別です。
8変更後の値で再整列する
点数を変更した後、同じキーで並べ直します。
active.sort(key=lambda r: r["score"], reverse=True)現在の点数で再整列; print([(r["name"], r["score"]) for r in active])更新された順序Aya80、Jun70、Mei0になります。抽出、表示変換、並べ替え、値の変更を別々に捉えると、どの一覧に何が反映されるか確認しやすくなります。
まとめ
除外する条件と出力値を変える条件を、内包表記の位置で使い分けます。
並べ替えの安定性、戻り値、要素の共有、再整列の必要性を確認します。
操作履歴と解説を振り返れます。
Python 3
rows = [{"name":"Mei","score":80,"active":True}, {"name":"Ken","score":95,"active":False}, {"name":"Aya","score":80,"active":True}, {"name":"Jun","score":70,"active":True}]; print([(r["name"],r["score"],r["active"]) for r in rows])[('Mei', 80, True), ('Ken', 95, False), ('Aya', 80, True), ('Jun', 70, True)]active = [r for r in rows if r["active"]]; print([r["name"] for r in active], len(rows), len(active))['Mei', 'Aya', 'Jun'] 4 3
display = [(r["name"], r["score"] if r["active"] else 0) for r in rows]; print(display)[('Mei', 80), ('Ken', 0), ('Aya', 80), ('Jun', 70)]ranked = sorted(active, key=lambda r: r["score"], reverse=True); print([(r["name"], r["score"]) for r in ranked]); print([r["name"] for r in rows])[('Mei', 80), ('Aya', 80), ('Jun', 70)]
['Mei', 'Ken', 'Aya', 'Jun']named_rank = sorted(active, key=lambda r: (-r["score"], r["name"])); print([(r["name"], r["score"]) for r in named_rank])[('Aya', 80), ('Mei', 80), ('Jun', 70)]returned = active.sort(key=lambda r: r["score"], reverse=True); print(returned, [r["name"] for r in active])None ['Mei', 'Aya', 'Jun']
active[0]["score"] = 0; print([(r["name"],r["score"]) for r in active]); print([(r["name"],r["score"]) for r in rows]); print([(r["name"],r["score"]) for r in ranked])[('Mei', 0), ('Aya', 80), ('Jun', 70)]
[('Mei', 0), ('Ken', 95), ('Aya', 80), ('Jun', 70)]
[('Mei', 0), ('Aya', 80), ('Jun', 70)]active.sort(key=lambda r: r["score"], reverse=True); print([(r["name"], r["score"]) for r in active])[('Aya', 80), ('Jun', 70), ('Mei', 0)]演習完了