'take a number and sum its digits

I'm working through this Kata and although I've looked through the solutions none are quite similar enough to mine to answer my question.

Problem Text: The number 89 is the first integer with more than one digit that fulfills the property partially introduced in the title of this kata. What's the use of saying "Eureka"? Because this sum gives the same number.

In effect: 89 = 8^1 + 9^2

The next number in having this property is 135.

See this property again: 135 = 1^1 + 3^2 + 5^3

We need a function to collect these numbers, that may receive two integers a, b that defines the range [a, b] (inclusive) and outputs a list of the sorted numbers in the range that fulfills the property described above.

def sum_dig_pow(a, b): # range(a, b + 1) will be studied by the function
    # your code here
    lst = []
    n = 1
    tot = 0
    for i in range(a,b):
        if i > 9:
            spl = str(i).split()
            for item in spl:
                tot += int(item) ** n
                n += 1
                if tot == i:
                    lst.append(i)
        else:
            lst.append(i)
    return lst

Tests are returning "[1, 2, 3, 4, 5, 6, 7, 8, 9, 10] should equal [1, 2, 3, 4, 5, 6, 7, 8, 9, 89]". I cannot figure out why it's passing 10 and not appending 89. I'm sure there's a more efficient way to do this as well but I'm still learning so want to be working in basics of loops, conditionals,etc.

Thanks everyone for your feedback! I know enumerate is really useful bc ive used it in the past but i couldn't quite conceptualize how it was helpful here >.< . Here's the solution that worked for me, plz comment with clean ups, etc!!

def sum_dig_pow(a, b): # range(a, b + 1) will be studied by the function
lst = []
for i in range(a,b+1):
    if i > 9:
       s = sum_dig(i)
       if s == i:
           lst.append(i)
    else:
        lst.append(i)
return lst

def sum_dig(num):
n = 1
tot = 0
for dig in str(num):
    tot += int(dig)**n
    n+=1
return tot


Solution 1:[1]

This line is incorrect:

spl = str(i).split()

The split method will split a string on spaces by default and return a list. So passing i=10 gives back spl = ['10'], a list with one element. Instead, just iterate over each of the digits in the string.

for item in str(i):
    ...

Follow up: you can shorten your code by using enumerate to count the index of each digit.

def sum_dig_pow(a,b):
    return [sum(int(y)**(i+1) for i,y in enumerate(str(x))) for x in range(a,b)]

Solution 2:[2]

Rather than spending a lot of time converting things from numbers to strings and back, try using arithmetic. To iterate over the digits of a number n, take n modulo ten (to get the least-significant digit) and then divide by ten (to peel off that least-significant digit). For example, the digits of 123 (in reverse order) are [(123 % 10), (12 % 10), (1 % 10)]

Thinking of it in terms of functions, first get the digits:

def digits_of_n(n):
  result = []
  while n > 0:
    result.append(n % 10)
    n = n / 10  # in python 3, use 3 // 10 for integer division
  return reversed(result) # reverse list to preserve original order

then get the sum of the powers:

def sum_of_ith_powers(numbers):
  result = 0
  for i, n in enumerate(numbers):  # the digits are ordered most-significant to least, as we would expect
    result += n ** 1
  return result

now you can just call sum_of_ith_powers(digits_of_n(n)) and you have an answer. If you like, you can give that operation a name:

def sum_of_digit_powers(n):
  return sum_of_ith_powers(digits_of_n(n))

and you can then name the function that solves the kata:

def solve_kata(a, b):
  return [sum_of_digit_powers(n) for n in range (a, b)]

Solution 3:[3]

You can use a generator, sum and enumerate in order to simplify your code like this example:

def sum_dig_pow(a,b):
    for k in range(a,b+1):
        if k > 9:
            number_sum = sum(int(j)**i for i,j in enumerate(str(k), 1))
            if k is number_sum:
                yield k
        else:
            yield k

print(list(sum_dig_pow(1,10)))
print(list(sum_dig_pow(1,90)))
print(list(sum_dig_pow(1,10000)))
print(list(sum_dig_pow(10,1000)))
print(list(sum_dig_pow(1,900000)))

Output:

[1, 2, 3, 4, 5, 6, 7, 8, 9]
[1, 2, 3, 4, 5, 6, 7, 8, 9, 89]
[1, 2, 3, 4, 5, 6, 7, 8, 9, 89, 135, 175]
[89, 135, 175]
[1, 2, 3, 4, 5, 6, 7, 8, 9, 89, 135, 175]

Solution 4:[4]

li = []
def sum_dig_pow(a, b):
    for i in range(a, b+1):
        sum1 = 0
        for ind, val in enumerate(str(i), 1):
            sum1 += pow(int(val), int(ind))
        if i == sum1:
            li.append(i)
    return li
print(sum_dig_pow(1, 11))

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2
Solution 3
Solution 4