全機能を統合しよう
どこから手を付けるか
ここからは総合制作です。新しい文法はもう出てきません。これまでに書いてきた関数をつなぎ直して、1 つのアプリとして動かします。
本物のメニューなら、while True で回しながら input() で番号を受け取り、打たれた番号で処理を振り分けます。ただし採点環境にはキーボードがつながっていないので、input() は使えません。そこで、打ち込まれるはずだった操作をあらかじめリストにして引数で渡す 形にします。
やっていることは同じです。input() から 1 行ずつ受け取る代わりに、リストから 1 つずつ取り出すだけの違いで、ループの中身は変わりません。外から来る値を引数で受け取る形にしておくと動作を確かめられる、というのは実務でも同じです。
コマンドは「操作名 + 必要な値」のリストで、3 種類だけ使います。
Python
["add", "りんご", 120, "食費"]
["delete", "りんご"]
["summary"]add は 1 件追加、delete は品名が一致する記録を 1 件だけ削除、summary は集計を見せるだけで記録を変えません。知らない操作名が来ても落とさずに無視します。
戻り値は最後の状態をまとめた辞書で、キーは 3 つに固定します。
Python
{"records": [{"name": "りんご", "price": 120, "category": "食費"}], "count": 1, "total": 120}1 つずつ足して、そのつど確かめる
全部をいっぺんに書こうとすると、どこで間違えたのか分からなくなります。順番はこうします。
まず add だけを処理して、記録が 1 件増えることを確かめます。次に空のコマンド列を渡し、records が空リスト、count と total が 0 で返ることを見ます。ここまでで骨組みができます。
そのうえで delete を足します。品名が一致する記録を 1 件だけ消す仕様なので、同じ品名が 2 件あるデータで試すのが要です。最後に、知らない操作名や summary を混ぜても落ちないことを確かめます。カテゴリが空文字のときに "その他" へ置き換わるかも、ここで見ておきます。
つまずくのは、たいてい 3 か所
1 つ目は、操作名より先に値を取り出してしまうことです。["summary"] は要素が 1 つしかないので、いきなり 2 番目を読むと IndexError になります。操作名で分岐したあと、その枝の中で取り出します。
2 つ目は、削除で全部消してしまうことです。同じ品名が 2 件あるとき、消し続ければ両方消えます。1 件だけ消すなら、消した時点でその探索を打ち切ります。
3 つ目は、合計を追加のたびに作り直すことです。delete が入るとずれます。全部のコマンドを処理し終えてから、残った記録を数えるほうが確実です。件数は自分で数えなくても len が返してくれます。
やってみよう
関数 run_kakeibo(commands) を実装してください。commands はコマンドのリストです。
add で記録を 1 件追加し、delete で品名が一致する記録を 1 件だけ消し、summary と知らない操作は何もしません。カテゴリが空文字のときは "その他" にします。最後に {"records": 記録のリスト, "count": 件数, "total": 合計金額} の辞書を返します。空のコマンド列なら records は空リスト、count と total は 0 です。
要件
- 関数名は run_kakeibo で、引数はコマンドのリスト commands 1つだけ
- add は {"name": 品名, "price": 金額, "category": カテゴリ} を1件追加する
- delete は品名が一致する記録を1件だけ消す。該当がなければ何もしない
- summary と知らない操作名は何もしない。エラーにもしない
- カテゴリが空文字のときは その他 に置き換える
- 戻り値は records と count と total の3つのキーを持つ辞書にする