Weekly Challenge 386
Each week Mohammad S. Anwar sends out The Weekly Challenge, a chance for all of us to come up with solutions to two weekly tasks. My solutions are written in Python first, and then converted to Perl. Unless otherwise stated, Copilot (and other AI tools) have NOT been used to generate the solution. It's a great way for us all to practice some coding.
Task 1: Reverse Base
Task
You are given a string representing a number, and an integer specifying the base of that representation.
Write a function to convert this string to an integer. (For bases greater than 10, use characters A-Z, a-z, + and / in that order.)
My solution
This is the reserve of a previous challenge where we converted numbers to a specified base. In this challenge, I start by defining the variable alphabet which has the first base characters from 0-9A-Za-z+/
import string
def reverse_base(input_string: str, base: int) -> int:
alphabet = "0123456789" + string.ascii_uppercase + string.ascii_lowercase + "+/"
alphabet = alphabet[:base]
I then convert each charter to its decimal representation. This uses list comprehension to find the index (position) of the character in the alphabet variable. If a value is invalid, a ValueError is raised, and I raise an Exception to state this.
try:
digits = [alphabet.index(digit) for digit in input_string]
except ValueError:
raise ValueError("Invalid input for the specified base")
The last part is to calculate the integer value, and return the output variable.
output = 0
for digit in digits:
output *= base
output += digit
return output
The Perl solution follows the same logic.
Examples
$ ./ch-1.py 101010 2
42
$ ./ch-1.py EEADEE 16
15642094
$ ./ch-1.py 755 8
493
$ ./ch-1.py 1BRJB 36
2228519
$ ./ch-1.py 7MyqL 64
123456789
Task 2: Rational Numbers
Task
You are given two strings representing non-negative rational numbers.
Write a script to return true if the two given rational numbers are same otherwise false.
My solution
For this challenge, I take two or more numbers. I start by split each rats (rational number) value into three parts: 1) The whole number (or 0 if not present), 2) The non-recurring fraction (or "" if not present), and 3) The recurring part of the fraction (or 0 if not present). This is stored in a list (array in Perl) called rat_parts.
def same_rational_numbers(*rats) -> bool:
rat_parts = []
for rat in rats:
m = re.search(r"(\d+)(?:\.(\d*)(?:\((\d+)\))?)?$", rat)
if not m:
raise ValueError("The value {rat} is invalid!")
rat_parts.append([m.group(1) or "0", m.group(2) or "", m.group(3) or "0"])
The next thing I do is check if the whole part of the numbers are the same. By using a set, duplicate values are removed. If there is more than one unique whole number, it means the values in rat aren't the same. For the Perl solution, I use uniq from the List::Util module to check for uniqueness.
if len(set(r[0] for r in rat_parts)) != 1:
return False
The last part to is check if the fraction part is the same. For this I set the part length to the maximum of length the non-recurring fraction and two times the recurring amount. This should cover all cases. The extend_part function takes the split parts, and extends the fractional part of part_length length.
def extend_part(rat_part, part_length) -> str:
s = rat_part[1]
while len(s) < part_length:
s += rat_part[2]
return s[:part_length]
Like with the whole check, the fraction part also uses a set (or uniq in Perl) to check that all parts are the same.
part_length = max(len(r[1]) + 2 * len(r[2]) for r in rat_parts)
if len(set(extend_part(r, part_length) for r in rat_parts)) != 1:
return False
return True
Like with the first task, the Perl solution follows the same logic.
Examples
In the challenge, the solution to the fourth example gives a different result. I believe this is an error in the example, not in my code.
$ ./ch-2.py "0.(12)" "0.(121)"
false
$ ./ch-2.py "0.1(23)" "0.12(32)"
true
$ ./ch-2.py "0.1(234)" "0.12(342)"
true
$ ./ch-2.py "12.99(99)" "13."
false
$ ./ch-2.py "0.(123)" "0.1(231)"
true
Top comments (0)