Решение на Телефонна любов от Виктор Христов

Обратно към всички решения

Към профила на Виктор Христов

Резултати

  • 9 точки от тестове
  • 0 бонус точки
  • 9 точки общо
  • 34 успешни тест(а)
  • 3 неуспешни тест(а)

Код

def nums_to_text(nums):
def next_digit(nums, i, forward_by, value):

Въпреки, че вероятно ползваш функцията само в nums_to_text е хубаво такива функции (особено долната, която е в пъти по-голяма) да се дефинират top-level.
Когато ще ги ползваш на много места ясно - нямаш избор. Но дори и в случая ще е по-четимо.

if i + forward_by < len(nums):
return nums[i + forward_by] == value
else:
return False
def numbers_to_letter(nums, string, i, in_case, letter_one, letter_two, letter_three, letter_four):

Винаги можеш да имаш следното:

def numbers_to_letter(nums, string, i, in_case, letter_one, letter_two, letter_three, letter_four=''):

По този начин можеш да викаш функцията както с 3, така и с 4 букви.

Това настрана обаче, такъв тип сигнатури обикновено говорят за лош дизайн. Многото вложени if-ове също.
Би следвало нещо от този сорт, да върши същата работа:

def numbers_to_letter(nums, string, i, in_case, *letters):
    for next, letter in enumerate(letters):
        if not next_digit(nums, i, next, in_case):
            string += letter
            i += next

Примерно... Не съм тествал, пиша го наизуст. Решава част от проблемите на функцията (не че не работи, просто е много Fortran-ска логика, Python има по-добри начини).

if next_digit(nums, i, 1, in_case):
if next_digit(nums, i, 2, in_case):
if next_digit(nums, i, 3, in_case):
if letter_four == '-':
i += 2;
elif next_digit(nums, i, 4, in_case):
i += 3;
else:
string += letter_four;
i += 3;
else:
string += letter_three;
i += 2;
else:
string += letter_two;
i += 1;
else:
string += letter_one;
return i, string
i = 0
string = ""
while i < len(nums):
match (nums[i]):
case 2:
i, string = numbers_to_letter(nums, string, i, 2, 'A', 'B', 'C', '-')
case 3:
i, string = numbers_to_letter(nums, string, i, 3, 'D', 'E', 'F', '-')
case 4:
i, string = numbers_to_letter(nums, string, i, 4, 'G', 'H', 'I', '-')
case 5:
i, string = numbers_to_letter(nums, string, i, 5, 'J', 'K', 'L', '-')
case 6:
i, string = numbers_to_letter(nums, string, i, 6, 'M', 'N', 'O', '-')
case 7:
i, string = numbers_to_letter(nums, string, i, 7, 'P', 'Q', 'R', 'S')
case 8:
i, string = numbers_to_letter(nums, string, i, 8, 'T', 'U', 'V', '-')
case 9:
i, string = numbers_to_letter(nums, string, i, 9, 'W', 'X', 'Y', 'Z')
case 0:
string += " "
i += 1
return string;
def text_to_nums(text):
def letter_to_numbers(letter, button_letters, previous_digit, nums, button_digit):
if previous_digit == button_digit:
nums.append(-1)
if letter == button_letters[0]:
nums.append(button_digit)
elif letter == button_letters[1]:
nums = nums + [button_digit, button_digit]
elif len(button_letters) == 4 and letter == button_letters[3]:
nums = nums + [button_digit, button_digit, button_digit, button_digit]
else:
nums = nums + [button_digit, button_digit, button_digit]
return nums, button_digit
text = text.upper()
previous_digit = 1
nums = []
for letter in text:
if ['A', 'B', 'C'].count(letter) > 0:
nums, previous_digit = letter_to_numbers(letter, ['A', 'B', 'C'], previous_digit, nums, 2)
elif ['D', 'E', 'F'].count(letter) > 0:
nums, previous_digit = letter_to_numbers(letter, ['D', 'E', 'F'], previous_digit, nums, 3)
elif ['G', 'H', 'I'].count(letter) > 0:
nums, previous_digit = letter_to_numbers(letter, ['G', 'H', 'I'], previous_digit, nums, 4)
elif ['J', 'K', 'L'].count(letter) > 0:
nums, previous_digit = letter_to_numbers(letter, ['J', 'K', 'L'], previous_digit, nums, 5)
elif ['M', 'N', 'O'].count(letter) > 0:
nums, previous_digit = letter_to_numbers(letter, ['M', 'N', 'O'], previous_digit, nums, 6)
elif ['P', 'Q', 'R', 'S'].count(letter) > 0:
nums, previous_digit = letter_to_numbers(letter, ['P', 'Q', 'R', 'S'], previous_digit, nums, 7)
elif ['T', 'U', 'V'].count(letter) > 0:
nums, previous_digit = letter_to_numbers(letter, ['T', 'U', 'V'], previous_digit, nums, 8)
elif ['W', 'X', 'Y', 'Z'].count(letter) > 0:
nums, previous_digit = letter_to_numbers(letter, ['W', 'X', 'Y', 'Z'], previous_digit, nums, 9)
elif letter == ' ':
nums.append(0)
previous_digit = 0
return nums
def nums_to_angle(nums):
degrees = 0
for num in nums:
if num == 0:
degrees += 300
else:
degrees += 30 * num
while degrees > 360:
degrees -= 360
return degrees
def angles_to_nums(angles):
def normalise(angle):
if angle > 0:
while angle > 360:
angle -= 360
else:
while angle < 0:
angle += 360
return angle
def stabilise(angle):
if angle % 30 == 0:
return angle
if angle >= 300:
lower_angle = 300
higher_angle = 360
elif angle >= 270:
lower_angle = 270
higher_angle = 300
elif angle >= 240:
lower_angle = 240
higher_angle = 270
elif angle >= 210:
lower_angle = 210
higher_angle = 240
elif angle >= 180:
lower_angle = 180
higher_angle = 210
elif angle >= 150:
lower_angle = 150
higher_angle = 180
elif angle >= 120:
lower_angle = 120
higher_angle = 150
elif angle >= 90:
lower_angle = 90
higher_angle = 120
elif angle >= 60:
lower_angle = 60
higher_angle = 90
elif angle >= 30:
lower_angle = 30
higher_angle = 60
else:
lower_angle = 0
higher_angle = 30
if abs(angle - lower_angle) <= abs(angle - higher_angle):
return lower_angle
else:
return higher_angle
nums = []
for angle in angles:
angle = stabilise(normalise(angle))
if angle < 300 and angle != 0:
nums.append(int(angle / 30))
return nums
def is_phone_tastic(word):
return nums_to_angle(text_to_nums(word)) % len(word) == 0

Лог от изпълнението

.......F..E......F...................
======================================================================
ERROR: test_empty_input (test.TestIsPhonetastic)
Test with empty input.
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/storage/deedee/data/rails/pyfmi-2022/releases/20221020151654/lib/language/python/runner.py", line 67, in thread
    raise result
ZeroDivisionError: integer division or modulo by zero

======================================================================
FAIL: test_random_mixed_case (test.TestAnglesToNums)
Test with a random mixed input.
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/storage/deedee/data/rails/pyfmi-2022/releases/20221020151654/lib/language/python/runner.py", line 67, in thread
    raise result
AssertionError: Lists differ: [5, 1, 2, 4, 9, 1, 8, 9] != [5, 1, 2, 4, 9, 1, 8, 0, 9]

First differing element 7:
9
0

Second list contains 1 additional elements.
First extra element 8:
9

- [5, 1, 2, 4, 9, 1, 8, 9]
+ [5, 1, 2, 4, 9, 1, 8, 0, 9]
?                       +++


======================================================================
FAIL: test_normalizing_for_top_boundary (test.TestNumsToAngles)
Test normalizing when the sum is full circle.
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/storage/deedee/data/rails/pyfmi-2022/releases/20221020151654/lib/language/python/runner.py", line 67, in thread
    raise result
AssertionError: 360 != 0

----------------------------------------------------------------------
Ran 37 tests in 0.455s

FAILED (failures=2, errors=1)

История (1 версия и 9 коментара)

Виктор обнови решението на 01.11.2022 21:58 (преди над 1 година)

+def nums_to_text(nums):
+ def next_digit(nums, i, forward_by, value):

Въпреки, че вероятно ползваш функцията само в nums_to_text е хубаво такива функции (особено долната, която е в пъти по-голяма) да се дефинират top-level.
Когато ще ги ползваш на много места ясно - нямаш избор. Но дори и в случая ще е по-четимо.

+ if i + forward_by < len(nums):
+ return nums[i + forward_by] == value
+ else:
+ return False
+
+ def numbers_to_letter(nums, string, i, in_case, letter_one, letter_two, letter_three, letter_four):

Винаги можеш да имаш следното:

def numbers_to_letter(nums, string, i, in_case, letter_one, letter_two, letter_three, letter_four=''):

По този начин можеш да викаш функцията както с 3, така и с 4 букви.

Това настрана обаче, такъв тип сигнатури обикновено говорят за лош дизайн. Многото вложени if-ове също.
Би следвало нещо от този сорт, да върши същата работа:

def numbers_to_letter(nums, string, i, in_case, *letters):
    for next, letter in enumerate(letters):
        if not next_digit(nums, i, next, in_case):
            string += letter
            i += next

Примерно... Не съм тествал, пиша го наизуст. Решава част от проблемите на функцията (не че не работи, просто е много Fortran-ска логика, Python има по-добри начини).

+ if next_digit(nums, i, 1, in_case):
+ if next_digit(nums, i, 2, in_case):
+ if next_digit(nums, i, 3, in_case):
+ if letter_four == '-':
+ i += 2;
+ elif next_digit(nums, i, 4, in_case):
+ i += 3;
+ else:
+ string += letter_four;
+
+ i += 3;
+ else:
+ string += letter_three;
+
+ i += 2;
+ else:
+ string += letter_two;
+
+ i += 1;
+ else:
+ string += letter_one;
+
+ return i, string
+
+ i = 0
+ string = ""
+
+ while i < len(nums):
+ match (nums[i]):
+ case 2:
+ i, string = numbers_to_letter(nums, string, i, 2, 'A', 'B', 'C', '-')
+ case 3:
+ i, string = numbers_to_letter(nums, string, i, 3, 'D', 'E', 'F', '-')
+ case 4:
+ i, string = numbers_to_letter(nums, string, i, 4, 'G', 'H', 'I', '-')
+ case 5:
+ i, string = numbers_to_letter(nums, string, i, 5, 'J', 'K', 'L', '-')
+ case 6:
+ i, string = numbers_to_letter(nums, string, i, 6, 'M', 'N', 'O', '-')
+ case 7:
+ i, string = numbers_to_letter(nums, string, i, 7, 'P', 'Q', 'R', 'S')
+ case 8:
+ i, string = numbers_to_letter(nums, string, i, 8, 'T', 'U', 'V', '-')
+ case 9:
+ i, string = numbers_to_letter(nums, string, i, 9, 'W', 'X', 'Y', 'Z')
+ case 0:
+ string += " "
+
+ i += 1
+
+ return string;
+
+def text_to_nums(text):
+ def letter_to_numbers(letter, button_letters, previous_digit, nums, button_digit):
+ if previous_digit == button_digit:
+ nums.append(-1)
+
+ if letter == button_letters[0]:
+ nums.append(button_digit)
+ elif letter == button_letters[1]:
+ nums = nums + [button_digit, button_digit]
+ elif len(button_letters) == 4 and letter == button_letters[3]:
+ nums = nums + [button_digit, button_digit, button_digit, button_digit]
+ else:
+ nums = nums + [button_digit, button_digit, button_digit]
+
+ return nums, button_digit
+
+ text = text.upper()
+ previous_digit = 1
+ nums = []
+
+ for letter in text:
+ if ['A', 'B', 'C'].count(letter) > 0:
+ nums, previous_digit = letter_to_numbers(letter, ['A', 'B', 'C'], previous_digit, nums, 2)
+ elif ['D', 'E', 'F'].count(letter) > 0:
+ nums, previous_digit = letter_to_numbers(letter, ['D', 'E', 'F'], previous_digit, nums, 3)
+ elif ['G', 'H', 'I'].count(letter) > 0:
+ nums, previous_digit = letter_to_numbers(letter, ['G', 'H', 'I'], previous_digit, nums, 4)
+ elif ['J', 'K', 'L'].count(letter) > 0:
+ nums, previous_digit = letter_to_numbers(letter, ['J', 'K', 'L'], previous_digit, nums, 5)
+ elif ['M', 'N', 'O'].count(letter) > 0:
+ nums, previous_digit = letter_to_numbers(letter, ['M', 'N', 'O'], previous_digit, nums, 6)
+ elif ['P', 'Q', 'R', 'S'].count(letter) > 0:
+ nums, previous_digit = letter_to_numbers(letter, ['P', 'Q', 'R', 'S'], previous_digit, nums, 7)
+ elif ['T', 'U', 'V'].count(letter) > 0:
+ nums, previous_digit = letter_to_numbers(letter, ['T', 'U', 'V'], previous_digit, nums, 8)
+ elif ['W', 'X', 'Y', 'Z'].count(letter) > 0:
+ nums, previous_digit = letter_to_numbers(letter, ['W', 'X', 'Y', 'Z'], previous_digit, nums, 9)
+ elif letter == ' ':
+ nums.append(0)
+ previous_digit = 0
+
+ return nums
+
+def nums_to_angle(nums):
+ degrees = 0
+
+ for num in nums:
+ if num == 0:
+ degrees += 300
+ else:
+ degrees += 30 * num
+
+ while degrees > 360:
+ degrees -= 360
+
+ return degrees
+
+def angles_to_nums(angles):
+ def normalise(angle):
+ if angle > 0:
+ while angle > 360:
+ angle -= 360
+ else:
+ while angle < 0:
+ angle += 360
+
+ return angle
+
+ def stabilise(angle):
+ if angle % 30 == 0:
+ return angle
+
+ if angle >= 300:
+ lower_angle = 300
+ higher_angle = 360
+ elif angle >= 270:
+ lower_angle = 270
+ higher_angle = 300
+ elif angle >= 240:
+ lower_angle = 240
+ higher_angle = 270
+ elif angle >= 210:
+ lower_angle = 210
+ higher_angle = 240
+ elif angle >= 180:
+ lower_angle = 180
+ higher_angle = 210
+ elif angle >= 150:
+ lower_angle = 150
+ higher_angle = 180
+ elif angle >= 120:
+ lower_angle = 120
+ higher_angle = 150
+ elif angle >= 90:
+ lower_angle = 90
+ higher_angle = 120
+ elif angle >= 60:
+ lower_angle = 60
+ higher_angle = 90
+ elif angle >= 30:
+ lower_angle = 30
+ higher_angle = 60
+ else:
+ lower_angle = 0
+ higher_angle = 30
+
+ if abs(angle - lower_angle) <= abs(angle - higher_angle):
+ return lower_angle
+ else:
+ return higher_angle
+
+ nums = []
+
+ for angle in angles:
+ angle = stabilise(normalise(angle))
+
+ if angle < 300 and angle != 0:
+ nums.append(int(angle / 30))
+
+ return nums
+
+def is_phone_tastic(word):
+ return nums_to_angle(text_to_nums(word)) % len(word) == 0

Адаш, има прекалено много if-ове, много логика като за C и най-страшното - табулации.
Не съм ти оставял бележки на всичко, което ми е направило впечатление, защото нерядко самият дизайн, който си избрал те обвързва с лошата практика, която бих коментирал.

Не ме разбирай грешно, покрил си изискванията много екстензивно и вероятно решението ти ще работи доста добре. Но ако не гледаме успешните тестове, а написаният код - твърдо не-питонски е. :)