CHAPTER 1 ・ 書き方を一段上げる / Lesson 05
並べ替えと、組み合わせ(sorted・zip)
金額順・日付順の並べ替え、2つのリストの突き合わせ、番号付けと、条件の一括判定を覚えます。
このレッスンが終わったら
「sorted の key で並べ替えの基準を指定できる。zip は2つの列を横に組み、enumerate は番号を付けてくれる」と言える。
こんな場面、ありませんか?
「売上の多い順に並べたい」「名前の一覧と金額の一覧を、並べて見たい」。報告書づくりでは、データの順番や組み合わせを変える作業が、何度も出てきます。
名前と金額を、別々のリストで持っているとき、金額だけを大きい順に並べると、こうなります。
▶ 実行を押すと、ここに結果が出ます
金額は大きい順に並びましたが、誰の金額かが分からなくなりました。名前のリストは、元の順番のままです。CSVの行(名前も金額も入った1行のかたまり)を、ひとまとめのまま並べ替えたいところです。
この回では、そのための sorted の key、2つのリストを横に組む zip、番号を付ける enumerate、そして「全員が条件を満たすか」を一括で調べる any / all を学びます。
sorted と zip を動かしてみる
sales.csv の6行から、売上の上位3件を取り出します。1行ずつのまとまり(辞書)を、売上の大きい順に並べ、先頭の3つを取ります。
この欄では、サンプルファイルが使えます。実行のたびに、ファイルは最初の状態に戻ります。
▶ 実行を押すと、ここに結果が出ます
月と部署が、売上といっしょに並び替わりました。key= で「何を基準に並べるか」を教えているのが、ポイントです。
次は zip です。2つのリストを、先頭から1つずつ組にして取り出します。
▶ 実行を押すと、ここに結果が出ます
key と lambda を読む
sorted の呼び出しを、部品に分けてみます。
sorted(rows並べ替えたいリストkey=並べ替えの基準を渡すlambda row:1行を「row」と呼ぶ小さな関数int(row["売上"])基準にする値(売上を数値に)reverse=True大きい順(降順)日本語にすると
lambda は、名前のない小さな関数です。基礎編の def で作る関数と、同じ働きを1行で書けます。key には、「1行を受け取って、並べ替えの基準になる値を返す関数」を渡します。
def で書く
def by_amount(row): return int(row["売上"]) sorted(rows, key=by_amount)
lambda で書く
sorted(rows, key=lambda row: int(row["売上"]))
変えて、試す
① 数字は、数値にして並べる。 CSVから読んだ売上は、文字です。そのまま並べると、数字の大きさではなく、文字の並び順になります。
▶ 実行を押すと、ここに結果が出ます
1行目は 10000 が先頭です(1 が 8 や 9 より小さいため)。key の中で int(...) を付けていたのは、このためです。
② 複数の基準で並べる。 「部署の順に、同じ部署の中では売上が大きい順」のように、基準が2つあるときは、( ) で2つの値を組にして返します。大きい順にしたい値は、- を付けてマイナスにします。
この欄では、サンプルファイルが使えます。実行のたびに、ファイルは最初の状態に戻ります。
▶ 実行を押すと、ここに結果が出ます
③ key がないと、エラー。 辞書どうしは、大きい小さいを比べられません。基準を教えずに並べると、止まります。
この欄では、サンプルファイルが使えます。実行のたびに、ファイルは最初の状態に戻ります。
▶ 実行を押すと、ここに結果が出ます
TypeError('<' not supported ...)と出ます。「辞書どうしの大小は比べられない」という意味です。辞書のリストは、必ず key= を付けて並べると覚えましょう。
④ 番号を付ける、組を辞書にする。 enumerate は、1つずつ取り出すときに番号も付けてくれます。start=1 で、1から始まります。dict(zip(...)) は、2つのリストから辞書を作ります。
▶ 実行を押すと、ここに結果が出ます
最後の行に注意してください。zip は、短いほうに合わせて終わります。名前が3人なのに金額が2つしかないと、3人目は何の知らせもなく消えます。突き合わせる前に、len() で長さが同じか確かめましょう。
⑤ 「全員が」「1つでも」を調べる。 all は「全部が True か」、any は「1つでも True か」を答えます。max / min にも key を付けられます。
この欄では、サンプルファイルが使えます。実行のたびに、ファイルは最初の状態に戻ります。
▶ 実行を押すと、ここに結果が出ます
内包表記(Lesson 01)で True / False のリストを作り、any / all に渡しています。[ ] を付けずに書くこともできますが、その意味は Lesson 21 で学びます。
自分で書く
お題① sales.csv から、売上の上位3件の金額を、大きい順の数値のリストで表示してください。
この欄では、サンプルファイルが使えます。実行のたびに、ファイルは最初の状態に戻ります。
▶ 実行を押すと、ここに結果が出ます
ヒントを見る
sorted(rows, key=lambda row: int(row["売上"]), reverse=True)[:3] で上位3行が取れます。そこから [int(row["売上"]) for row in top3] で金額だけを取り出します。
答えの例を見る
import csv
with open("sales.csv", encoding="utf-8") as f:
rows = list(csv.DictReader(f))
top3 = sorted(rows, key=lambda row: int(row["売上"]), reverse=True)[:3]
print([int(row["売上"]) for row in top3])お題② 名前のリストと金額のリストから、田中:12000円 の形の文字を並べたリストを作って、表示してください。
▶ 実行を押すと、ここに結果が出ます
ヒントを見る
[f"{n}:{a}円" for n, a in zip(names, amounts)] の形です。作ったリストを print で表示します。
答えの例を見る
names = ["田中", "佐藤", "鈴木"]
amounts = [12000, 8500, 23000]
labels = [f"{n}:{a}円" for n, a in zip(names, amounts)]
print(labels)お題③ 経費 costs について、「全件が10,000円以下か」と「1件でも10,000円以上があるか」を、all と any で調べ、1行ずつ表示してください。
▶ 実行を押すと、ここに結果が出ます
ヒントを見る
all([c <= 10000 for c in costs]) と、any([c >= 10000 for c in costs]) を、それぞれ print します。
答えの例を見る
costs = [1200, 540, 8800, 15400, 3300] print(all([c <= 10000 for c in costs])) print(any([c >= 10000 for c in costs]))
仕事ならどう使う?
理解チェックrows が辞書のリストのとき、「売上」(文字) を数値にして、小さい順に並べる書き方は、どれでしょう?
理解チェックnames が3人、amounts が2件のとき、zip(names, amounts) で取り出せる組は、いくつでしょう?