こんなのを見つけたので、また腕試しにトライしてみたぜ。ちと長くなっちゃったので前半後半にわける。3問目はコードを書く問題じゃなかったから抜かしてる。



1. アナグラム
2つの引数を取り、引数がアナグラム(どちらも全く同じ文字を含んでいる)ならばtrueを、そうでないならばfalseを返す関数をかけ。
def problem1(arg1, arg2):

    # まず引数チェックをします。
    if not (isinstance(arg1, str) and isinstance(arg2, str)):
        print(f'引数は文字列だけ認めるよ: {arg1}, {arg2}')
        return False

    # 長さが違う時点でダメです。
    if len(arg1) != len(arg2):
        print(f'長さが違う時点でダメ: {arg1}, {arg2}')
        return False

    # arg1の文字が全部arg2に同数含まれてるか? という判断基準でいく。
    for a in arg1:
        if arg1.count(a) != arg2.count(a):
            print(
                f'arg1の文字"{a}"がarg1には{arg1.count(a)}個あるけど'
                f'arg2には{arg2.count(a)}個あるよ: {arg1}, {arg2}'
            )
            return False

    print(f'OKだよーん: {arg1}, {arg2}')
    return True

実行結果。
print(problem1('abcde', 'edcba'), end='\n')
print(problem1('abcde', 'abcdei'), end='\n')
print(problem1('abcde', 1), end='\n')
print(problem1('abcde', 'edcbf'), end='\n')
print(problem1('日本語はどうでしょうね', 'ううしでどねはょ日本語'), end='\n')
print(problem1('ABA', 'ABB'), end='\n')
----------
OKだよーん: abcde, edcba
True
長さが違う時点でダメ: abcde, abcdei
False
引数は文字列だけ認めるよ: abcde, 1
False
arg1の文字"a"がarg1には1個あるけどarg2には0個あるよ: abcde, edcbf
False
OKだよーん: 日本語はどうでしょうね, ううしでどねはょ日本語
True
arg1の文字"A"がarg1には2個あるけどarg2には1個あるよ: ABA, ABB
False

最近使いこなせるようになってきた isinstance とか楽しんで使ってみた。けどまあ、こういう問題を解くときはそういうのナシで短くまとめるようにしたほうが見栄えがよかったかと思わんでもない。



2. 税金計算
金額(ドル)と、税率(%)を引数にとり、答えの金額をセントとして配列で返せ。

これが曲者だった。ところでこれは、金額に税額を足せってことで合っているよな? ほんでその金額をドルとセントに分けて [ドル, セント] にしろってことだよな? 俺はそういう理解でやってみたぞ。

def problem2(dollar, tax_rate):

    if not (isinstance(dollar, float) and isinstance(tax_rate, float)):
        print(f'引数はfloatだけ認めるよ: {dollar}, {tax_rate}')
        return False

    dollar, tax_rate = str(dollar), str(tax_rate)

    # 小数点は右からいくつめにあるの? **.**** なら 4 を取得します。
    # [::-1]は文字列の反転。pt_lctnはpoint_locationのことです。
    dollar_pt_lctn = dollar[::-1].find('.')

    # 税率は%単位だから、最後に/100ぶんの2を足すよ。 *.* なら 3 を取得します。
    tax_rate_pt_lctn = tax_rate[::-1].find('.') + 2

    # ドル、税率から小数点を削除ります。晴れてintになりました。さらばfloat。
    dollar_int = int(str(dollar).replace('.', ''))
    tax_rate_int = int(str(tax_rate).replace('.', ''))

    # 税金額を出します。floatでやると誤差が生じてワヤになるからintで。
    tax_amount = dollar_int * tax_rate_int

    # 元のドルを税金額に桁あわせします。float同士だと足し算ですら狂うのでintでやります。
    # 小数点を削除ったドルに、税率の小数点の位置ぶん0加えたものがそれ。
    original_dollar = int(str(dollar_int) + '0' * tax_rate_pt_lctn)

    # 元のドルに税金額を足します。
    result = str(original_dollar + tax_amount)

    # 削除ってた小数点を戻します。
    # 位置は、最初に削除ったふたつの小数点の位置を足したところ。
    # 100.1ドル と 9.75% だったら 右から5番目になる。(%ぶんの+2を忘れずに。)
    pt_lctn = dollar_pt_lctn + tax_rate_pt_lctn
    result_ = (str(result)[0:-pt_lctn] + '.' + str(result)[-pt_lctn:])

    print(f'額は ${result_} になりました。結果の配列は下に表示されます。')

    # なんやかんやで $***.***** を [***, **.***] にして返します。
    dollar_part = str(result)[0:-pt_lctn]
    dollar_part = int(dollar_part if dollar_part else '0')
    cent_part = str(result)[-pt_lctn:] + '0'
    cent_part = float(cent_part[0:2] + '.' + cent_part[2:])

    return [dollar_part, cent_part]

実行結果。
print(problem2(100.0, 8.00), end='\n')
print(problem2(0.10, 10.56), end='\n')
print(problem2(100.10, 9.75), end='\n')
print(problem2(100, 9.75), end='\n')
print(problem2(123.456789, 8.1234), end='\n')
print(problem2(4.64, 9.75), end='\n')
print(problem2(0.10, 10.56), end='\n')
print(problem2(1.0, 100.0), end='\n')
----------
額は $108.0000 になりました。結果の配列は下に表示されます。
[108, 0.0]
額は $.11056 になりました。結果の配列は下に表示されます。
[0, 11.056]
額は $109.85975 になりました。結果の配列は下に表示されます。
[109, 85.975]
引数はfloatだけ認めるよ: 100, 9.75
False
額は $133.485677797626 になりました。結果の配列は下に表示されます。
[133, 48.5677797626]
額は $5.092400 になりました。結果の配列は下に表示されます。
[5, 9.24]
額は $.11056 になりました。結果の配列は下に表示されます。
[0, 11.056]
額は $2.0000 になりました。結果の配列は下に表示されます。
[2, 0.0]

見づら。何この見づらい関数。それもこれもすべて float の計算が微妙に狂うせいなのだよ。
print(0.1 * 3)  # 0.30000000000000004 になる。なんでだよ。
print(0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1)  # 0.7999999999999999 になる。なんでだよ!!
なんかねえ、二進数が小数がうまく表せないせいで起こるらしいよこれは。そういうわけで float 同士の計算は避けようと思って上述のクソ長い関数は爆誕した。

のだが、のちにググったら「そういうときは Decimal を使え」とあってですね……。Decimalというのはintでもfloatでもない数値型で、正確な小数を表せるとかで。
import decimal

def problem2(dollar, tax_rate):

    # Decimal型(正確な小数)に変換します。
    dollar = decimal.Decimal(str(dollar))
    tax_rate = decimal.Decimal(str(tax_rate))

    # 元の額 + 税額
    result = dollar + dollar * (tax_rate / 100)

    # ドル部とセント部に分けます。
    return [int(result), float((result - int(result)) * 100)]
これで上述関数と同じ結果が出る。ほなら float を廃止して Decimal にしたほうがいいんじゃないの、pythonの旦那?



後半に続く。