総合 ポイント管理台帳
師範 / 目安 45分
松田さんが、机の上に手書きの帳面を積み上げて言いました。「集大成だ! 会員登録、ポイント付与、ランク一覧、それに保存。全部入りのやつを頼む!」。事務局の10問目、最後の依頼です。
ここまでで、付与の計算、ランクの判定、辞書での集計、ファイルへの保存を、それぞれ別々の道具として作ってきました。最後の課題は、その道具を1つの台帳にまとめることです。新しく覚える構文はありません。持っている道具を、正しい順番で組み上げられるかだけを問います。
事務局の窓口には、1日ぶんの操作が伝票の束になって届きます。台帳はその束を上から順に処理し、最後に締めの報告を出します。伝票には不備もあります。同じ人が二重に登録されていたり、登録されていない人へ付与が来たりします。不備は落とさず数えて報告するのが事務員の仕事です。
完成条件
run_ledger(operations) という関数を定義してください。
operations は操作を並べたリストです。1つの操作は [種別, 名前, 値] の3つ組で、種別は次の2つです。
"登録"— その名前の会員を、値を初期ポイントとして台帳の末尾に追加します"付与"— その名前の会員に、値を会計金額としてポイントを足します。付くポイントは 100円で1ポイント、端数は切り捨て です
不備の扱いは次のとおりです。どれも台帳を変えずに読み飛ばし、件数だけ数えます。
- すでに同じ名前が登録されているのに、また
"登録"が来た - 登録されていない名前へ
"付与"が来た - 種別が
"登録"でも"付与"でもない
全部の操作を処理し終えたら、台帳を ledger_final.txt に上書きモードで保存します。1行に1会員、名前,ポイント の形です。保存したらそのファイルを読み直し、読み直したデータをもとに締めの報告を組み立てて返してください。
返す辞書のキーは4つです。
members—{"name": ..., "points": ...}の辞書のリスト。並びは登録した順ranks— ランクごとの人数の辞書。ランクは1000以上が"ゴールド"、500以上が"シルバー"、それ未満が"ブロンズ"。該当者が0人のランクはキーごと入れませんtotal— 全会員の保有ポイントの合計skipped— 読み飛ばした不備の件数
進め方
白紙から書いてください。手が止まったらヒントを開けます。ヒントは3段階で、①方針、②使う構文、③部分解の順に出ます。1つも開けずに通せたら、その問題は自分のものです。
開かずに10分粘って進まないなら、①だけ開けてください。粘る時間そのものには価値がありません。価値があるのは、自分で書いた行が動いた瞬間です。
一息に書こうとすると必ず崩れます。付与の計算とランクの判定を先に小さな関数として切り出し、run_ledger はその2つを呼ぶだけにしてください。道場で何度も作ってきた形です。
ランクの境目はちょうど1000とちょうど500です。付与の割り算は切り捨てです。この2つを取り違えると、通らないのに原因が見えません。
これで10問すべてです。松田さんは帳面を閉じて、静かに言いました。「商店街のDX、完成や…!」
師範が奥から一枚の紙を持って出てきます。そこには Python道場・師範代を允許する と書かれていました。表示の1行から始めて、いまあなたは人の仕事を丸ごと引き受けるプログラムを、白紙から組み上げられます。
要件
- run_ledger(operations) を定義する。operations は [種別, 名前, 値] の3つ組のリスト
- 「登録」は名前と初期ポイントで会員を末尾に追加する
- 「付与」は値を会計金額として、100円で1ポイント(端数切り捨て)を足す
- 二重登録・未登録者への付与・未知の種別は台帳を変えずに読み飛ばし、件数を数える
- 処理後に ledger_final.txt へ上書きモードで「名前,ポイント」を1行1会員で保存する
- 保存したファイルを読み直し、そのデータから報告を組み立てる
- 返す辞書のキーは members(登録順の辞書のリスト)、ranks(ランクごとの人数、0人のランクは入れない)、total(合計ポイント)、skipped(読み飛ばした件数)の4つ
- ランクは1000以上がゴールド、500以上がシルバー、それ未満がブロンズ
入出力例
run_ledger([["登録","田中はじめ",0],["付与","田中はじめ",1250],["付与","田中はじめ",38800],["登録","佐藤みどり",200],["付与","佐藤みどり",30000]]) → {"members":[{"name":"田中はじめ","points":400},{"name":"佐藤みどり","points":500}],"ranks":{"シルバー":1,"ブロンズ":1},"skipped":0,"total":900}
run_ledger([["登録","松田さだお",300],["登録","佐藤みどり",0],["付与","佐藤みどり",50],["付与","鈴木たけし",9999],["登録","松田さだお",100],["解約","松田さだお",0]]) → {"members":[{"name":"松田さだお","points":300},{"name":"佐藤みどり","points":0}],"ranks":{"ブロンズ":2},"skipped":3,"total":300}
run_ledger([["登録","山口あゆみ",980],["付与","山口あゆみ",2050],["登録","中村けいた",500],["登録","小林ひかる",1200],["付与","中村けいた",99]]) → {"members":[{"name":"山口あゆみ","points":1000},{"name":"中村けいた","points":500},{"name":"小林ひかる","points":1200}],"ranks":{"ゴールド":2,"シルバー":1},"skipped":0,"total":2700}
run_ledger([]) → {"members":[],"ranks":{},"skipped":0,"total":0}ヒント
前のヒントを開くと次が開きます。開かずに解けると未開封クリアです