月間レポート機能
4 つの数字を、どの順で作るか
run_kakeibo で追加と削除ができるようになりました。ただ、記録が溜まっただけでは何も分かりません。「今月は何にいくら使ったのか」を一目で分かる形にするのが今回の仕事です。
レポートに載せるのは 4 つです。合計の total、カテゴリごとの合計を入れた by_category、いちばん高かった支出の品名 top、予算からの残り remaining。この 4 つをキーに持つ辞書を返します。
このうち total は第 6 章、by_category は第 7 章ですでに作りました。remaining は予算から合計を引くだけです。本当に新しいのは top だけなので、そこに時間を使います。完成間近のアプリに機能を足すとき、ゼロから考えることはめったにありません。
既習の合計・カテゴリ別集計・予算残りと戻り値の組み立ては、完成済みの _assemble_report(records, budget, top) に任せます。ひな形の最後で呼び出すので、その部分は変更しません。受講者が書くのは最高額の品名を選ぶ処理だけです。
最高額の探索と集計は、別々のループで扱います。1 つのループに複数の役割を詰め込まず、どの処理を直すか分かる形にします。まず 1 件で確かめ、次に同額の 2 件、0 円の記録という順で確かめましょう。
最高額の初期値を、どこに置くか
top を求めるには、「今までで一番高い金額」を覚えておく変数が要ります。この初期値が地味な勘所です。
0 から始めると、0 円の記録しかない月に 1 件も選ばれず、top が空文字のまま返ります。金額は 0 以上なので、必ずそれより小さい値、たとえば -1 から始めれば 1 件目で必ず入れ替わります。
同じ金額が 2 件並んだときの扱いも決めておきます。比較を「より大きい」にすれば先に出てきたほうが残り、「以上」にすれば後のほうへ入れ替わります。今回は先に出てきたほうを採用します。比較の違いを身長の数値で確かめると、次のようになります。
Python
print(150 > 150) # False なので同じ身長では入れ替えない
print(150 >= 150) # True なので同じ身長でも入れ替える
print(0 > -1) # True なので初期値が -1 なら 0 も選べる最高額の探索でも、この比較の違いを使います。どちらでもよい仕様ですが、決めていないコードはいつか必ず食い違います。
なお top に入れるのは品名の文字列です。金額を覚えておく変数は探すための作業用で、戻り値には入れません。
記録が 0 件のときを、先に確かめる
初回起動や月が変わった直後は、記録が空です。ここを最初に通しておくと、あとが楽になります。
Python
monthly_report([], 3000)期待する戻り値は {"total": 0, "by_category": {}, "top": "", "remaining": 3000} です。ループが 1 度も回らないので、それぞれの初期値がそのまま返ります。初期値を素直に置いておけば、空リスト用の場合分けは要りません。
逆に、予算を超えた月も確かめます。remaining は 0 で止めず、負の数のまま返します。-1300 と出るからこそ、いくら超えたのかが分かります。
やってみよう
関数 monthly_report(records, budget) の最高額を選ぶ部分を実装してください。records は支出の辞書のリスト、金額は 0 以上の整数、budget は予算の整数です。ひな形にある top の空文字と最後の return はそのまま使い、作業用の最高額の初期値と探索処理を書きます。
{"total": 合計金額, "by_category": カテゴリ別の合計の辞書, "top": 最高額の品名, "remaining": 予算から合計を引いた値} の辞書を返します。同じ金額が並んだときは先に出てきたほうを top にします。記録が空のときは top を ""、by_category を {}、remaining を budget にしてください。
要件
- 関数名は monthly_report で、引数は records と budget の 2 つ。金額は 0 以上の整数
- 受講者は作業用の最高額の初期値と、最高額の品名 top を選ぶ探索処理を書く
- top は最高額の品名。同額なら先に出てきたほうを採用する
- 0 円の記録しかない場合も最初の品名を選ぶ。記録が空なら top は空文字のまま
- top の初期値と最後の return はそのまま使う。補助関数が total・by_category・top・remaining の辞書を返す
- 補助関数はカテゴリごとに金額を足し、remaining を budget - total とする。空なら by_category は空辞書で予算が残り、超過なら負の数を返す