Не получается определить счастливое число

Задача:

Счастливое число — это число, определённое следующим процессом: начиная с любого положительного целого числа, мы заменяем это число суммой квадратов его цифр в десятичной системе счисления и повторяем данный процесс, пока число либо не станет равно 1 (где весь процесс остановится), или попадёт в бесконечный цикл, не содержащий 1. Числа, для которых данный процесс заканчивается единицей, называются счастливыми числами, в то время как те, для которых процесс не заканчивается единицей, считаются несчастливыми числами.

Напишите функцию, которая определяла бы является ли заданное число N счастливым.

Входные данные: N - натуральное число от 1 до 1000.

Вывод: true/false - является ли число счастливым.

Примеры

N = 19
1^2 + 9^2 = 82
8^2 + 2^2 = 68
6^2 + 8^2 = 100
1^2 + 0^2 + 0^2 = 1.
Output: true
N = 2;
Output: false

Код:

def happy(n):
    numbers = list(map(int, str(n)))
    res = sum([i ** 2 for i in numbers])
    if res == 1:
        return True
    elif len([i for i in numbers if i != 0]) == 1:
        return False
    else:
        happy(res)


print(happy(19))

выводит None

Хотя в дебагере появлялась 1 и по идее return должен сработать. Так почему функция выявляет что сумма квадратов равна 1 и все равно потом лезет в else?


Ответы (1 шт):

Автор решения: n1tr0xs

Ответ уже дали в комментариях (@godva) - вы забыли return в блоке else.
Я лишь дам несколько советов:

  1. Слово else можно не писать. Код туда и так не дойдет при выполнении одного из предыдущих условий:
def happy(n):
    numbers = list(map(int, str(n)))
    res = sum([i ** 2 for i in numbers])
    if res == 1:
        return True
    elif len([i for i in numbers if i != 0]) == 1:
        return False
    return happy(res)
  1. В sum можно передать генератор, а не список:
res = sum(i ** 2 for i in numbers)
  1. Лучше использовать i*i вместо i**2 (из-за особенностей реалилизации возведения в степень python будет быстрее i*i)
res = sum(i*i for i in numbers)
  1. В elif можно не использовать оператор !=:
elif len([i for i in numbers if i]) == 1:
   return False
  1. Еще лучше будет, если сразу отфильтровать numbers:
numbers = list(filter(bool, map(int, str(n))))

ну или так, если не любите filter:

numbers = [i for i in map(int, str(n)) if i]

Итог:

def happy(n):
    numbers = list(filter(bool, map(int, str(n))))
    res = sum(i*i for i in numbers)
    if res == 1:
        return True
    elif len(numbers) == 1:
        return False
    return happy(res)

"Ужатая версия":

def happy(n):
    numbers = list(filter(bool, map(int, str(n))))
    res = sum(i*i for i in numbers)
    return True if res==1 else False if len(numbers)==1 else happy(res)

Ну и решение без рекурсии:

def happy(n):
    while True:
        numbers = list(filter(bool, map(int, str(n))))
        n = sum(i*i for i in numbers)
        if n == 1:
            return True
        if len(numbers)==1:
            return False
→ Ссылка