📜 ⬆️ ⬇️

0b1001 ways to solve the problem of converting numbers to the Roman notation

image

Hello friends. Here you have a simple little problem. How would you translate arabic numbers to roman using python? True with one condition - the numbers can not be more than 4000.

I think it should be easy, but let me show you a series of interesting solutions and non-trivial approaches:

"13 steps" from StefanPochmann


Very simple idea and at the same time the most popular. We make a table of correspondences of Arabic and Roman numbers. Following the table of these correspondences, we reduce the Arabic number and increase the Roman number.
')
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 

I added the print function for you so that the solution is clearer. And what will be the conclusion:

 >>> 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' 

Now you see how the Roman and Arabic numbers change at each iteration.

"Thous, hunds, tens and ones" by 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 

In this case, we already have an inverse correspondence of the Arab to the Roman. In this case, we no longer need a cycle.

"Base.replace" by MaikSchoepe


 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 

I believe that this is not the most effective way to solve, but one of the most fun. It starts with what makes a long string of “I”, the size of the number transferred. The next order replaces every five “I” characters with the “V” character. Then two “V” on “X” and so on. At the end of the path we get the string we were looking for.

"Enum" from veky


In order to understand how the following solution works, you need to know the Enum module. If you do not know - there is a great chance to google it.

 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)) 

In general, the example works the same as we saw in the first example from StefanPochmann, but with some syntactic syntax. Such as enum and yield

"A derelict battery" by veky


I collected all these solutions with CheckiO .

And when a user publishes his decision on this resource, he must choose in which category he wants to add it. There is such a category as “Creative”, where you don’t have to bother much about speed or how easy your decision is to read. The only thing you have to think about is how creative and unusual your decision is.

This decision is just from this category.

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

Yes, that's all. It is worth mentioning, however, that the formater module has been closed since version 3.4 due to the fact that very few people have used it. So we’ll probably write Guido’s petition to leave this module in Python. Your up-and-down for this decision - you somehow put your signature on this petition.

“Enough elegant, but not very Pythonic” from nathan.l.cook


We move on and decisions get harder.

 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 = 0​ for 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 += 2​ return ans 

You know, when you read someone's decision and the first lines you see it:

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

Do you think: “Ok, there will definitely be some magic here”

“A bit of history from” from veky (or from ...)


 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() 

You can know the author of this solution from books like The Art of Computer Programming, Concrete Mathematics, Surreal Numbers, and so on.

"This Strange Roman Mathematics" by LukeSolo


Quite often you meet solutions on CheckiO, and at the same time you have no idea how they work:

 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 

But I think you will figure it out :)

thank


In the list of used materials, I added links to CheckiO solutions of users that I used in this article. By clicking on them, you can read the code review of other users or write your own.

This is the first time when I try to share this collection of the most interesting solutions on CheckiO . Let me know how interesting it is for you to read about it and how much you like the format itself.

CheckiO user solutions were used to create this article:


PS: By the way, there is still the “Speedy” category for solutions. And when you say that the solution to the problem can not be longer than 4000 characters, then this is the quickest solution for this task. For obvious reasons, I can only show you the link.

Source: https://habr.com/ru/post/311678/


All Articles