0b1001数字をローマ字表記に変換する問題を解決する方法

画像



こんにちは友人。 簡単なタスクを次に示します。 Pythonを使用してアラビア数字をローマ字にどのように変換しますか? 1つの条件の真実-数値は4000を超えることはできません。



シンプルにすべきだと思いますが、一連の興味深い解決策と重要なアプローチを紹介します。



StefanPochmannによる13のステップ



非常にシンプルなアイデアであると同時に最も人気があります。 アラビア数字とローマ数字の対応表を作成します。 これらの通信の表に従って、アラビア数字を減らし、ローマ数字を増やします。



def checkio(n): result = '' for arabic, roman in zip((1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1), 'M CM D CD C XC L XL X IX V IV I'.split()): result += n // arabic * roman n %= arabic print('({}) {} => {}'.format(roman, n, result)) return result
      
      





ソリューションを明確にするために、印刷機能を追加しました。 そして、ここに結論があります:



 >>> checkio(177) (M) 177 => (CM) 177 => (D) 177 => (CD) 177 => (C) 77 => C (XC) 77 => C (L) 27 => CL (XL) 27 => CL (X) 7 => CLXX (IX) 7 => CLXX (V) 2 => CLXXV (IV) 2 => CLXXV (I) 0 => CLXXVII 'CLXXVII'
      
      





これで、繰り返しごとにローマ数字とアラビア数字がどのように変化するかがわかります。



mdeakyneによる「数千、数十、数十」



 def checkio(data): ones = ["","I","II","III","IV","V","VI","VII","VIII","IX"] tens = ["","X","XX","XXX","XL","L","LX","LXX","LXXX","XC"] hunds = ["","C","CC","CCC","CD","D","DC","DCC","DCCC","CM"] thous = ["","M","MM","MMM","MMMM"] t = thous[data // 1000] h = hunds[data // 100 % 10] te = tens[data // 10 % 10] o = ones[data % 10] return t+h+te+o
      
      





この場合、アラブ人とローマ人の間にはすでに逆の対応があります。 さらに、サイクルはもう必要ありません。



MaikSchoepeによる「Base.replace」



 def checkio(data): base = "I"*data base = base.replace("I"*5, "V") base = base.replace("V"*2, "X") base = base.replace("X"*5, "L") base = base.replace("L"*2, "C") base = base.replace("C"*5, "D") base = base.replace("D"*2, "M") base = base.replace("DCCCC", "CM") base = base.replace("CCCC", "CD") base = base.replace("LXXXX", "XC") base = base.replace("XXXX", "XL") base = base.replace("VIIII", "IX") base = base.replace("IIII", "IV") return base
      
      





これは最も効果的な解決方法ではなく、最も楽しい方法の1つだと思います。 まず、送信された番号のサイズである「I」の長い文字列を作成します。 次の行は、5つの「I」文字ごとに「V」文字に置き換えます。 次の2つの「V」から「X」など。 パスの最後に、探していた文字列を取得します。



vekyによる「Enum」



次のソリューションがどのように機能するかを理解するには、Enumモジュールを知る必要があります。 わからない場合は、グーグルで検索する絶好のチャンスです。



 from enum import Enum​ class Roman(Enum): M = 1000 CM = 900 D = 500 CD = 400 C = 100 XC = 90 L = 50 XL = 40 X = 10 IX = 9 V = 5 IV = 4 I = 1​ @classmethod def encode(cls, n): for numeral in cls: rep, n = divmod(n, numeral.value) yield numeral.name * rep​ checkio = lambda n: ''.join(Roman.encode(n))
      
      





一般に、この例は、StefanPochmannの最初の例で見たのと同じように機能しますが、いくつかの構文糖を使用しています。 enumやyieldなど



vekyによる「遺棄されたバッテリー」



これらすべてのソリューションをCheckiOで収集しました



また、ユーザーがこのリソースに関する決定を公開するとき、追加するカテゴリを選択する必要があります。 「クリエイティブ」などのカテゴリがあります。このカテゴリでは、速度のトピックやソリューションの読みやすさについてあまり気にする必要はありません。 あなたが考えるべき唯一のことは、あなたの決断がどれほど創造的で珍しいかです。



この決定は、このカテゴリーからのものです。



 import formatter, functools checkio = functools.partial(formatter.AbstractFormatter.format_roman, None, 'I')
      
      





はい、それだけです。 ただし、バージョン3.4以降、ほとんどの人が使用していないため、フォーマッタモジュールは非アクティブ化されています。 そのため、このモジュールをPythonのままにするというGuidoの請願書を作成する可能性が高くなります。 この決定に賛成票を投じて、あなたは何らかの形でこの請願書に署名をします。



nathan.l.cookの「優雅に十分ですが、あまりPython的ではありません」



私たちは先へ進み、意思決定は難しくなります



 def checkio(data): rom = ['I', 'V', 'X', 'L', 'C', 'D', 'M'] str_data = str(data) str_data = str_data[::-1] num_digits = len(str_data) ans = "" rom_pointer = 0for place in range(num_digits): if str_data[place] in ["0", "1", "2", "3"]: ans = rom[rom_pointer] * int(str_data[place]) + ans elif str_data[place] in ["4"]: ans = rom[rom_pointer] + rom[rom_pointer + 1] + ans elif str_data[place] in ["5", "6", "7", "8"]: ans = rom[rom_pointer + 1] + rom[rom_pointer] * (int(str_data[place]) - 5) + ans elif str_data[place] in ["9"]: ans = rom[rom_pointer] + rom[rom_pointer + 2] + ans rom_pointer += 2return ans
      
      





誰かのソリューションを読んだとき、最初の行は次のとおりです。



  str_data = str(data) str_data = str_data[::-1]
      
      





あなたは思う:「わかりました、ここには間違いなく何らかの魔法があります」



veky(または...)からの「少しの歴史」



 def checkio(n:int) -> str: pool = "m2d5c2l5x2v5i" rep = lambda t: int(pool[t - 1]) def roman(n, j=0, v=1000): while True: while n >= v: yield pool[j]; n -= v if n <= 0: return k = j + 2; u = v // rep(k) if rep(k) == 2: k += 2; u //= rep(k) if n + u >= v: yield pool[k]; n += u else: j += 2; v //= rep(j) return "".join(roman(n)).upper()
      
      





このソリューションの作成者は、コンピュータープログラミングの芸術、コンクリート数学、シュールナンバーなどの本から知ることができます。



ルークソロによる「この奇妙なローマの数学」



多くの場合、CheckiOでソリューションに出くわしますが、同時にそれらがどのように機能するのかわかりません。



 from math import sqrt​ alpha = "IVXLCDM" one = lambda n, s: (n % 5 >> n % 5 // 4 * 2) * alpha[s] two = lambda n, s: (3 < n) * alpha[s + (3 < n) + (8 < n)] three = lambda n, s: sqrt(n) == int(sqrt(n)) and ''.join(reversed(s)) or s go = lambda n, s: three(n, two(n, s) + one(n, s))​ def checkio(data, s = 0, conc = ""): d, m = divmod(data, 10) text = go(m, s) + conc return d and checkio(d, s + 2, text) or text
      
      





しかし、あなたはそれを理解するだろうと思う:)



ありがとう



使用した資料のリストに、この記事で使用したCheckiOユーザーのソリューションへのリンクを追加しました。 それらをクリックすると、他のユーザーのコードレビューを読んだり、自分で書いたりできます。



CheckiOで最も興味深いソリューションのコレクションを共有しようとするのは初めてです。 これについて読んだり、フォーマット自体がどれだけ気に入っているのかをお読みください。



この記事を作成するために、 CheckiOユーザーのソリューションを使用しました。





PS:ところで、ソリューションにはまだ「スピーディ」カテゴリがあります。 また、問題の解決策が4000文字を超えることはできないと言う場合、これがこのタスクの最速の解決策です。 明らかな理由から、リンクのみを表示できます。



All Articles