一覧PG-08-3 · コレクションの操作

データの抽出・変換・並べ替え

四人のレコードから対象者を抽出し、点数と名前で並べ替えます。元の一覧、並べ替え後の一覧、各レコードの共有関係を確認し、値を変更した後に順序を更新します。

説明

一覧の加工では、要素を除外する処理と、値を別の形へ変換する処理を分けます。並べ替えは比較用のキーを指定でき、同じキーの要素は元の順序を保ちます。

四人のレコードから対象者を抽出し、点数と名前で並べ替えます。元の一覧、並べ替え後の一覧、各レコードの共有関係を確認し、値を変更した後に順序を更新します。

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

1
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)]
2
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
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)]
4
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']
5
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)]
6
returned = active.sort(key=lambda r: r["score"], reverse=True); print(returned, [r["name"] for r in active])
None ['Mei', 'Aya', 'Jun']
7
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)]
8
active.sort(key=lambda r: r["score"], reverse=True); print([(r["name"], r["score"]) for r in active])
[('Aya', 80), ('Jun', 70), ('Mei', 0)]

演習完了