Celem tego zadania jest dodanie do siebie wszystkich cyfr z danej liczby i zaprezentowanie wyniku. Zrobimy to sobie na co najmniej 2 sposoby obrazujące różne podejścia do tego tematu
Sposób pierwszy – konwersja, redukcja
Tutaj spróbujemy skonwertować typ liczbowy do typu znakowego a następnie do listy, w jakiś sposób dokonać redukcji tej listy z powrotem do typu liczbowego, zawierającego podliczoną wartość wszystkich cyfr.
Brzmi strasznie, więc zaczynajmny. Konwersja do napisu:
num = 123
strnum = str(num)
print(strnum)
#123
Super, mamy liczbę zapisaną jako string. To znaczy, że teraz możemy zrobić z niej listę, której każdy element to będzie cyfra. Cyfra-napis, ale jednak cyfra.
num = 123
strnum = str(num)
print(strnum)
#123
lstnum = list(strnum)
print(lstnum)
# ['1', '2', '3']
Jest wiele sposobów, aby to osiągnąć, choćby list comprehension. Zachęcam do wypróbowywania nowych sposobów, natomiast ja skorzystam z funkcji reduce, znajdującej się w module functools.
Reduce redukuje listę według określonej funkcji. Funkcja przyjmuje akumulator i element. Akumulator ma wartość początkową przez nas wyznaczoną i to on będzie po redukcji zwrócony.
My chcemy, aby akumulator początkowo wynosił zero, zaś każdy element listy dostał zamieniony z cyfry-napisu na liczbę i do akumulatora dodany. Brzmi to groźniej, niż w kodzie wygląda, więc oto kod:
from functools import reduce
num = 123
strnum = str(num)
print(strnum)
#123
lstnum = list(strnum)
print(lstnum)
# ['1', '2', '3']
digits_sum = reduce(lambda x, y: x + int(y), lstnum, 0)
print(digits_sum)
#6
Czyli tak, używamy reduce. Funkcja lambda, 2 argumenty, x – akumulator, y -element. Do akumulatora dodajemy element wcześniej do liczby skonwertowany. Pracujemy na liście lstnum, wartość początkowa akumulatora to 0.
Może i skomplikowana ta logika reduce odrobinę i trzeba się do niej przyzwyczaić. Ale jak zrozumiemy jak to działa będziemy zapewne chętnie z tej akurat funkcji korzystać (wszystko co robią funkcje typu map bądź filter to akurat przy pomocy list comprehension osiągnąć możemy).
No dobra, zbierajmy tę logikę do kupy i twórzmy funkcję, która dodaje do siebie cyfry z danej liczby:
from functools import reduce
def add_digits(num):
lst_num = list(str(num))
return reduce(lambda x, y : x + int(y), lst_num, 0)
print(add_digits(123))
print(add_digits(111))
# 6
# 3
Aby z liczby zrobić listę cyfr musimy najpierw dokonać konwersji do napisu, dopiero później do listy, co czynimy. Następnie nasza redukcja, do akumulatora x, początkowo 0, dodajemy każdy element y zamieniony na typ liczbowy int zabrany z listy lst_num i to zwracamy.
Proste.
Sposób 2 – matematyczny w pętli
Spróbujmy inaczej do tego podejść i pracować tylko na typie liczbowym. Zapomnijmy o jakichkolwiek konwersjach. Chcemy zatem przejść po liczbie. Tyle razy, ile ma cyfr. Jak to zrobić?
Spróbujmy tak:
num = 123
while num:
print(num)
num = num // 10
# 123
# 12
# 1
Rzeczywiście, 3 cyfry są, mamy trzy obroty pętli. Dzięki dzieleniu przez 10 liczba za każdym razem skraca się o jedną cyfrę. Tego nie widzimy, ale po ostatnim obrocie pętli 1 zostaje podzielone bez reszty przez 10 i num wynosi 0, warunek while num (tak długo, jak num nie jest zerem) przestaje być prawdziwy.
No dobrze, mamy sposób na pętlę, która wykonuje tyle obrotów, ile ma cyfr. Ale nadal nie mamy patentu na to, aby dobrać się do tej ostatniej cyfry. My je chcemy dodać do siebie, a nie podać ilość cyfr.
Patent na „złapanie” ostatniej cyfry jest bardzo prosty. Reszta z dzielenia przez 10:
num = 123
while num:
print(num % 10)
num = num // 10
# 3
# 2
# 1
Reszta z dzielenia przez 10 czyli % 10 zawsze daje ostatnią cyfrę. Zaś dzielenie bez reszty przez 10 czyli // 10 zawsze ucina ostatnią cyfrę.
Nic więcej nie potrzebujemy, aby te cyferki do siebie dodać.
num = 123
sum = 0
while num:
sum += num % 10
num = num // 10
print(sum) #6
sum równe 0, tak długo jak num nie jest zerem (a będzie nim po trzykrotnym w tym wypadku podzieleniu bez reszty przez 10 czyli //10) dodajemy w pętli ostatnią cyfrę (wyciągniętą poprzez % 10 czyli resztę z dzielenia przez 10) i „ucinamy” ostatnią cyfrę.
Za pierwszym razem mamy 123. Dodajemy 3 i ucinamy ostatnią cyfrę (dzielenie przez 10 bez reszty). Potem 12, dodajemy ostatnią cyfrę i ucinamy. Potem 1, dodajemy ostatnią cyfrę i ucinamy.
Tak to działa. Teraz nic, tylko napisać funkcję do tego:
def count_digits(num):
sum = 0
while num:
sum += num % 10
num = num // 10
return sum
print(count_digits(123))
print(count_digits(111))
# 6
# 3
Warto odnotować zabawy z cyframi tego typu. Mogą się przydać do wielu rzeczy, choćby zamiany z systemu dziesiętnego na dwójkowy.