zipで組み合わせ
このレッスンで作るもの — 品名のリストと金額のリストを
zipで組み合わせ、りんご 120円の行に整えるpair_linesを作ります。
zip で組み合わせる
ここまでは 1 本のリストを回してきました。ところが実際のおこづかい帳では、品名と金額という 2 つの情報 が組になっています。
まだ辞書を習っていないので、いまは品名だけのリストと金額だけのリストに分かれている、という状況を考えます。
names = ["りんご", "みかん", "パン"]
prices = [120, 80, 250]りんご の値段は 120、みかん は 80、パン は 250 です。同じ位置どうしが対応している、という約束で並んでいます。
位置で対応させる並べ方は、ずれた瞬間に全部が狂います。だからこそ、ずれを持ち込まない書き方を選ぶ意味があります。
番号で取り出す書き方の弱点
素直に書くと、番号を使って両方から取り出すことになります。
for i in range(len(names)):
print(names[i] + " " + str(prices[i]) + "円")動きますが、i という番号がコードの主役になってしまいます。names[i] と prices[i] の片方だけ書き間違えると、品名と金額の組がずれます。しかも prices のほうが短いと IndexError で落ちます。
zip の形
zip は、複数のリストから 同じ位置の要素をまとめて 1 組ずつ 出してくれます。
for name, price in zip(names, prices):
print(name, price)これは りんご 120、みかん 80、パン 250 と表示します。enumerate のときと同じく、for のうしろに名前を 2 つ並べて受け取ります。番号を表す変数が消え、やりたいことだけがコードに残りました。
zip は 3 本以上のリストも受け取れます。zip(names, prices, categories) と書けば、for name, price, category in ... の形で 3 つ組を取り出せます。
長さが違うときは短いほうに合わせる
zip は、渡されたリストのうち いちばん短いもの に合わせて止まります。
names = ["りんご", "みかん", "パン"]
prices = [120, 80]
for name, price in zip(names, prices):
print(name, price)出るのは りんご 120 と みかん 80 の 2 組だけです。パン には相手がいないので捨てられます。エラーにならずに黙って切り捨てるので、そこは知っておく必要があります。
行をつないで返す
前のレッスンと同じ要領で、改行を行の手前に足しながら 1 本の文字列にします。
def pair_lines(names, prices):
result = ""
for name, price in zip(names, prices):
if result != "":
result = result + "\n"
result = result + name + " " + str(price) + "円"
return resultpair_lines(["りんご", "みかん"], [120, 80]) の結果は "りんご 120円\nみかん 80円" です。第 1 章で決め打ちしていたレシートの中身が、外から渡した値で作れるようになりました。
第 1 章の
make_receiptは 2 行を手で書いていました。いまは何件でも同じコードで組み立てられます。ループを覚えると、コードの長さと扱える件数が切り離せます。
よくある間違い
zipに渡し忘れる —for name, price in names:と書くと、品名 1 文字ずつを 2 つに分けようとしてValueErrorになります。組にするにはzipが要ります。- 金額を文字列に変え忘れる —
name + " " + priceはTypeErrorです。str(price)を挟みます。 - 長さのずれに気づかない —
zipは短いほうで止まり、余った分を黙って捨てます。件数が合うことを前提にするなら、lenを比べて確かめる処理を別途書きます。
どちらかが空のリストなら 1 組も出ないので、result は空文字のまま返ります。
やってみよう
関数 pair_lines を実装してください。引数は 2 つで、names は品名 (str) のリスト、prices は金額 (int) のリストです。
zip で同じ位置どうしを組にし、"りんご 120円" の形に整えた行を改行 \n でつないだ 1 本の文字列を return します。品名と金額のあいだは半角スペース 1 つ、金額のうしろは全角の 円 です。末尾に改行は付けません。
長さが違うときは zip の性質どおり、短いほうに合わせて切り上げます。どちらも空のときは空文字 "" を返します。
要件
- 関数名は pair_lines で、引数は names と prices の2つにする
- zip を使って同じ位置の品名と金額を組にして取り出す
- 各行は "りんご 120円" のように品名、半角スペース1つ、金額、全角の円 の順にする
- 行の区切りは \n を使い、末尾には改行を付けない
入出力例
pair_lines(["りんご","みかん","パン"], [120,80,250]) → "りんご 120円
みかん 80円
パン 250円"
pair_lines(["りんご"], [120]) → "りんご 120円"
pair_lines(["りんご","みかん","パン"], [120,80]) → "りんご 120円
みかん 80円"
pair_lines(["りんご"], [120,80,250]) → "りんご 120円"
pair_lines(["おまけ","パン"], [0,250]) → "おまけ 0円
パン 250円"
pair_lines([], []) → ""