CHAPTER 1 ・ 書き方を一段上げる / Lesson 05

並べ替えと、組み合わせ(sorted・zip)

金額順・日付順の並べ替え、2つのリストの突き合わせ、番号付けと、条件の一括判定を覚えます。

目安 18分 ・ インストール不要

このレッスンが終わったら

「sorted の key で並べ替えの基準を指定できる。zip は2つの列を横に組み、enumerate は番号を付けてくれる」と言える。

STEP 1

こんな場面、ありませんか?

「売上の多い順に並べたい」「名前の一覧と金額の一覧を、並べて見たい」。報告書づくりでは、データの順番や組み合わせを変える作業が、何度も出てきます。

名前と金額を、別々のリストで持っているとき、金額だけを大きい順に並べると、こうなります。

金額だけを並べ替えるとコードは書き換えられます
Ctrl / ⌘ + Enter でも実行
結果
▶ 実行を押すと、ここに結果が出ます

金額は大きい順に並びましたが、誰の金額かが分からなくなりました。名前のリストは、元の順番のままです。CSVの行(名前も金額も入った1行のかたまり)を、ひとまとめのまま並べ替えたいところです。

この回では、そのための sorted の key、2つのリストを横に組む zip、番号を付ける enumerate、そして「全員が条件を満たすか」を一括で調べる any / all を学びます。

STEP 2

sorted と zip を動かしてみる

sales.csv の6行から、売上の上位3件を取り出します。1行ずつのまとまり(辞書)を、売上の大きい順に並べ、先頭の3つを取ります。

売上の上位3件を取り出すサンプルファイル付き・書き換えOK
Ctrl / ⌘ + Enter でも実行

この欄では、サンプルファイルが使えます。実行のたびに、ファイルは最初の状態に戻ります。

結果
▶ 実行を押すと、ここに結果が出ます

月と部署が、売上といっしょに並び替わりました。key= で「何を基準に並べるか」を教えているのが、ポイントです。

次は zip です。2つのリストを、先頭から1つずつ組にして取り出します。

名前と金額を、組にして取り出すコードは書き換えられます
Ctrl / ⌘ + Enter でも実行
結果
▶ 実行を押すと、ここに結果が出ます
STEP 3

key と lambda を読む

sorted の呼び出しを、部品に分けてみます。

sorted(rows, key=lambda row: int(row["売上"]), reverse=True)
sorted(rows並べ替えたいリスト
key=並べ替えの基準を渡す
lambda row:1行を「row」と呼ぶ小さな関数
int(row["売上"])基準にする値(売上を数値に)
reverse=True大きい順(降順)

日本語にすると

rows の各行について、売上を数値にした値を基準にして、大きい順に並べ替えてください。

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["売上"]))
どちらも同じ結果です。1回しか使わない短い関数なら、lambda で十分です。
STEP 4

変えて、試す

① 数字は、数値にして並べる。 CSVから読んだ売上は、文字です。そのまま並べると、数字の大きさではなく、文字の並び順になります。

文字のまま並べると、数値の順にならないコードは書き換えられます
Ctrl / ⌘ + Enter でも実行
結果
▶ 実行を押すと、ここに結果が出ます

1行目は 10000 が先頭です(1 が 8 や 9 より小さいため)。key の中で int(...) を付けていたのは、このためです。

② 複数の基準で並べる。 「部署の順に、同じ部署の中では売上が大きい順」のように、基準が2つあるときは、( ) で2つの値を組にして返します。大きい順にしたい値は、- を付けてマイナスにします。

部署ごとに、売上の大きい順サンプルファイル付き・書き換えOK
Ctrl / ⌘ + Enter でも実行

この欄では、サンプルファイルが使えます。実行のたびに、ファイルは最初の状態に戻ります。

結果
▶ 実行を押すと、ここに結果が出ます

③ key がないと、エラー。 辞書どうしは、大きい小さいを比べられません。基準を教えずに並べると、止まります。

わざと間違える:key を付けずに辞書を並べるサンプルファイル付き・書き換えOK
Ctrl / ⌘ + Enter でも実行

この欄では、サンプルファイルが使えます。実行のたびに、ファイルは最初の状態に戻ります。

結果
▶ 実行を押すと、ここに結果が出ます

TypeError('<' not supported ...)と出ます。「辞書どうしの大小は比べられない」という意味です。辞書のリストは、必ず key= を付けて並べると覚えましょう。

④ 番号を付ける、組を辞書にする。 enumerate は、1つずつ取り出すときに番号も付けてくれます。start=1 で、1から始まります。dict(zip(...)) は、2つのリストから辞書を作ります。

順位つきで表示する・辞書にするコードは書き換えられます
Ctrl / ⌘ + Enter でも実行
結果
▶ 実行を押すと、ここに結果が出ます

最後の行に注意してください。zip は、短いほうに合わせて終わります。名前が3人なのに金額が2つしかないと、3人目は何の知らせもなく消えます。突き合わせる前に、len() で長さが同じか確かめましょう。

⑤ 「全員が」「1つでも」を調べる。 all は「全部が True か」、any は「1つでも True か」を答えます。max / min にも key を付けられます。

all・any・max・sumサンプルファイル付き・書き換えOK
Ctrl / ⌘ + Enter でも実行

この欄では、サンプルファイルが使えます。実行のたびに、ファイルは最初の状態に戻ります。

結果
▶ 実行を押すと、ここに結果が出ます

内包表記(Lesson 01)で True / False のリストを作り、any / all に渡しています。[ ] を付けずに書くこともできますが、その意味は Lesson 21 で学びます。

STEP 5

自分で書く

お題① sales.csv から、売上の上位3件の金額を、大きい順の数値のリストで表示してください。

お題①:売上上位3件の金額サンプルファイル付き・書き換えOK
Ctrl / ⌘ + Enter でも実行

この欄では、サンプルファイルが使えます。実行のたびに、ファイルは最初の状態に戻ります。

結果
▶ 実行を押すと、ここに結果が出ます
ヒントを見る

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円 の形の文字を並べたリストを作って、表示してください。

お題②:名前と金額を組み合わせるコードは書き換えられます
Ctrl / ⌘ + Enter でも実行
結果
▶ 実行を押すと、ここに結果が出ます
ヒントを見る

[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行ずつ表示してください。

お題③:全員が条件を満たすかコードは書き換えられます
Ctrl / ⌘ + Enter でも実行
結果
▶ 実行を押すと、ここに結果が出ます
ヒントを見る

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]))
STEP 6

仕事ならどう使う?

理解チェックrows が辞書のリストのとき、「売上」(文字) を数値にして、小さい順に並べる書き方は、どれでしょう?

理解チェックnames が3人、amounts が2件のとき、zip(names, amounts) で取り出せる組は、いくつでしょう?