私自身が表題の問題を解いた時のプログラムについて解説します。
問題の詳細は「バスの料金を計算しよう(初級編)」(CodeIQ)を参照してください。
| 幼児 | 子供 | 大人 | |
|---|---|---|---|
| 記号 | I | C | A |
| 料金 | 後述 | 大人の半額 (10円未満切り上げ) |
標準料金 |
Pythonで解答しています。
#!/usr/local/bin/python3
import fileinput
import math
# 子供料金を計算する
def CalcChildPrice(lst):
ret = []
for i in lst:
n = 10 * math.ceil((i // 10) / 2)
ret.append(n)
return ret
# 入力文字列をパースする
def parseLine(str):
ret = []
price, passenger = str.split(":")
ret.append(passenger.split(","))
ret.append(list(map(int, price.split(","))))
ret.append(CalcChildPrice(ret[1]))
return ret
# 乗客の大人、子供、幼児の数を数える
def countPassenger(lst):
p = {"A":0, "C":0, "I":0}
for k,v in p.items():
p[k] = len(list(filter(lambda a:a==k, lst)))
return p
# 金額計算
# p 乗客を数えたもの
# ap 大人の金額
# cp 子供の金額
def calcTotal(p, ap, cp):
price_dic = {
"A": sum(ap),
"C": sum(cp),
"I": sum(cp),
}
cnt_i = p["I"] - (2*p["A"])
if cnt_i < 0:
cnt_i = 0
target = {
"A": p["A"],
"C": p["C"],
"I": cnt_i,
}
ret = 0
for k, v in target.items():
ret += v * price_dic[k]
return ret
#==============================================================================
# main
#------------------------------------------------------------------------------
for line in fileinput.input():
if not line.strip():
continue
PassengerList, PliceListA, PliceListC = parseLine(line.strip())
PassengerCount = countPassenger(PassengerList)
total = calcTotal(PassengerCount, PliceListA, PliceListC)
print(total)
ポイントは幼児の扱いと10円未満での切り上げ処理でしょうか。そこさえクリアすれば困るとことはありません。
parseLine()ですが入力書式が複雑なのでパース処理も複雑です。
この関数は入力値を「乗員リスト」、「大人料金リスト」、「子供料金リスト」を返します。
乗員リストは入力値を「:」で分割した後半部分を「,」で分割したものです。
大人料金リストは入力値を「:」で分割した前半部分を「,」で分割し、数値に変換したもの。
子供料金リストは大人料金リストを半額にし10円未満を切り上げたものです。
乗員のリスト(文字のリスト)を大人X人、子供Y人、幼児X人というディクリョナリに変換します。
calcTotal()で最終的な計算をします。
35〜37行目は大人、子供、幼児の料金を計算します。ループで単純に処理できるように幼児料金は子供料金と同じですがセットします。
41〜43行目で無料になる幼児を人数から引いています。最低値が0なのでif文ではその処理をします。 45〜49の処理で最終的に計算する人数を処理対象のディクショナリに設定しています。引数pのp["I"]を書き換えても同じですが引数を破壊的に扱いたくないので別変数に設定しています。
ここまでの処理でA、C、Iそれぞれの料金、計算対象の人数が決まったので最後に値段×人数をA、C、Iごとに計算して合計して終わりです。
こういうタイプの問題を見るとほっとします。
私がプログラムを書く上で気をつけていることの一つに、なるべくifやswitchを使わなくて良いようにするというのがあります。条件分岐があるとそこでコードを2つの流れに分けて考えなければならなくなるので可読性が悪くなるからです。
少々メモリ効率が悪くても処理が単純になるようにした方が良いというのが私の持論です(私が会社に入って時ですでにそれほどメモリが厳しいということはなかったので、今となってはさらにそうでしょう)。