I cannot loop through a string in a function - python

I want to create a function that can take a positive integer n as input and return the sum of all that number's digit.
Below is my code:
def digit_sum(n):
string = str(n)
for number in string:
num = int(number)
total = 0
total += num
return total
but the error message is :
Your function fails on digit_sum(434). It returns 4 when it should return 11.
To my knowledge is that the for loop doesn't loop successfully. It only loops one time then return the value.
My questions are:
what' wrong with my code?
The reason I need to convert the number into string first is that integer cannot iterable?
Hope anyone could help me out.
Thanks!!

The problem is that you are setting total equal to zero within the loop. What this means is each pass through it adopts the most recent value, o + num, which in the last digit of this string is 4. Instead, try this:
def digit_sum(n):
string = str(n)
total = 0
for number in string:
num = int(number)
total += num
return total

The problem is that you are resetting the value of total back to 0 with each iteration of the loop. Move the initialization to above the loop, like this
def digit_sum(n):
string = str(n)
total = 0
for number in string:
num = int(number)
total += num
return total

You are resetting total on each iteration. Move total = 0 outside of the for loop.

Related

Python: error invalid literal for int() with base 10

My task is to find how many times we need to multiply digits of a number until only one digit left and count how many "turns" we need to take until that 1 digit left.
Example:
39 -> 3*9=27 -> 2*7=14 -> 1*4=4, so the answer should be 3.
So far I got:
def persistence(n):
count = 1
sum = int(str(n)[0:1]) * int(str(n)[1:2])
while(n > 0 or sum > 9):
sum = int(str(sum)[0:1]) * int(str(sum)[1:2])
count = count + 1
print(sum)
print("how many times: " + count)
persistence(39)
So how I approached this task:
I take first 2 digits convert them to str and multiply them.
Already with first sum I go to while loop and keep repeating that.
So, my problem is that I keep getting this:
How can I solve it? Or should I try to approach this task differently?
You only have a couple of problems.
The while loop keeps checking n. It only needs to check sum
The final print tries to add an int to a str. Just use print arguments instead.
def persistence(n):
count = 1
sum = int(str(n)[0:1]) * int(str(n)[1:2])
while sum > 9:
sum = int(str(sum)[0:1]) * int(str(sum)[1:2])
count = count + 1
print(sum)
print("how many times: ", count)
persistence(39)
Output as expected.
However, you should not use sum as the name of a variable. You can reuse n instead:
def persistence(n):
count = 1
n = int(str(n)[0:1]) * int(str(n)[1:2])
while n > 9:
n = int(str(n)[0:1]) * int(str(n)[1:2])
count = count + 1
print(n)
print("how many times: ", count)
This should work.
def returnLength(n):
return len(str(n))
def returnProduct(n, pro=1):
n = str(n)
for i in n:
pro *= int(i)
return pro
n = int(input())
c = 0
while returnLength(n) != 1:
n = returnProduct(n)
c += 1
print(c)
So basically at the start my program had Achilles heel, because it's failed when I had 3+ digit number. I read every suggestion very carefully and my final code went like this:
def persistence(n):
def returnLength(n):
return len(str(n))
def returnProduct(n, pro=1):
n = str(n)
for i in n:
pro *= int(i)
return pro
c = 0
while n > 9:
n = returnProduct(n)
c += 1
print(c)
However, I still couldn't pass the test nevertheless everything worked fine on VScode and I did some random manual testing (I'm practicing at codewars.com and a lot of people wrote that on this task's test might have a bug). It might be that I can have only one def. I will try to figure that out. Once again, thank you all.

Recursion function to count how many times a certain sequence appears

I am writing a recursive function that takes an integer as input and it will return the number of times 123 appears in the integer.
So for example:
print(onetwothree(123123999123))
Will print out 3 because the sequence 123 appears 3 times in the number I entered into the function.
Here is my code so far:
def onetwothree(x):
count = 0
while(x > 0):
x = x//10
count = count + 1
if (count < 3): #here i check if the digits is less than 3, it can't have the sequence 123 if it doesn't have 3 digits
return 0
if (x%10==1 and x//10%10 == 2 and x//10//10%10==3):
counter += 1
else:
return(onetwothree(x//10))
This keeps printing "0".
I think you are overthinking recursion. A solution like so should work:
def onetwothree(n, count=0):
if n <= 0:
return count
last_three_digits = n % 1000
n_without_last_number = n // 10
if last_three_digits == 123:
return onetwothree(n_without_last_number, count + 1)
else:
return onetwothree(n_without_last_number, count)
print(onetwothree(123123999123))
Outputs:
3
If you want to count how many times '123' occurs in a number, why not convert your number from an integer to a string and use str.count?
Then your function would look like this:
def onetwothree(x):
return str(x).count('123')
But it would also not be recursive anymore.
You could also just use the line print(str(123123999123).count('123')) which is pretty much the same as using it with the onetwothree function.
I hope this answer helps :)

How can I display all numbers in range 0-N that are "super numbers"

The program asks the user for a number N.
The program is supposed to displays all numbers in range 0-N that are "super numbers".
Super number: is a number such that the sum of the factorials of its
digits equals the number.
Examples:
12 != 1! + 2! = 1 + 2 = 3 (it's not super)
145 = 1! + 4! + 5! = 1 + 24 + 120 (is super)
The part I seem to be stuck at is when the program displays all numbers in range 0-N that are "super numbers". I have concluded I need a loop in order to solve this, but I do not know how to go about it. So, for example, the program is supposed to read all the numbers from 0-50 and whenever the number is super it displays it. So it only displays 1 and 2 since they are considered super
enter integer: 50
2 is super
1 is super
I have written two functions; the first is a regular factorial program, and the second is a program that sums the factorials of the digits:
number = int(input ("enter integer: "))
def factorial (n):
result = 1
i = n * (n-1)
while n >= 1:
result = result * n
n = n-1
return result
#print(factorial(number))
def breakdown (n):
breakdown_num = 0
remainder = 0
if n < 10:
breakdown_num += factorial(n)
return breakdown_num
else:
while n > 10:
digit = n % 10
remainder = n // 10
breakdown_num += factorial(digit)
#print (str(digit))
#print(str(breakdown_num))
n = remainder
if n < 10 :
#print (str(remainder))
breakdown_num += factorial(remainder)
#print (str(breakdown_num))
return breakdown_num
#print(breakdown(number))
if (breakdown(number)) == number:
print(str(number)+ " is super")
Existing answers already show how to do the final loop to tie your functions together. Alternatively, you can also make use of more builtin functions and libraries, like sum, or math.factorial, and for getting the digits, you can just iterate the characters in the number's string representation.
This way, the problem can be solved in a single line of code (though it might be better to move the is-super check to a separate function).
def issuper(n):
return sum(math.factorial(int(d)) for d in str(n)) == n
N = 1000
res = [n for n in range(1, N+1) if issuper(n)]
# [1, 2, 145]
First I would slightly change how main code is executed, by moving main parts to if __name__ == '__main__', which will execute after running this .py as main file:
if __name__ == '__main__':
number = int(input ("enter integer: "))
if (breakdown(number)) == number:
print(str(number)+ " is super")
After that it seems much clearer what you should do to loop over numbers, so instead of above it would be:
if __name__ == '__main__':
number = int(input ("enter integer: "))
for i in range(number+1):
if (breakdown(i)) == i:
print(str(i)+ " is super")
Example input and output:
enter integer: 500
1 is super
2 is super
145 is super
Small advice - you don't need to call str() in print() - int will be shown the same way anyway.
I haven't done much Python in a long time but I tried my own attempt at solving this problem which I think is more readable. For what it's worth, I'm assuming when you say "displays all numbers in range 0-N" it's an exclusive upper-bound, but it's easy to make it an inclusive upper-bound if I'm wrong.
import math
def digits(n):
return (int(d) for d in str(n))
def is_super(n):
return sum(math.factorial(d) for d in digits(n)) == n
def supers_in_range(n):
return (x for x in range(n) if is_super(x))
print(list(supers_in_range(150))) # [1, 2, 145]
I would create a lookup function that tells you the factorial of a single digit number. Reason being - for 888888 you would recompute the factorial of 8 6 times - looking them up in a dict is much faster.
Add a second function that checks if a number isSuper() and then print all that are super:
# Lookup table for single digit "strings" as well as digit - no need to use a recursing
# computation for every single digit all the time - just precompute them:
faks = {0:1}
for i in range(10):
faks.setdefault(i,faks.get(i-1,1)*i) # add the "integer" digit as key
faks.setdefault(str(i), faks [i]) # add the "string" key as well
def fakN(n):
"""Returns the faktorial of a single digit number"""
if n in faks:
return faks[n]
raise ValueError("Not a single digit number")
def isSuper(number):
"Checks if the sum of each digits faktorial is the same as the whole number"
return sum(fakN(n) for n in str(number)) == number
for k in range(1000):
if isSuper(k):
print(k)
Output:
1
2
145
Use range.
for i in range(number): # This iterates over [0, N)
if (breakdown(number)) == number:
print(str(number)+ " is super")
If you want to include number N as well, write as range(number + 1).
Not quite sure about what you are asking for. From the two functions you write, it seems you have solid knowledge about Python programming. But from your question, you don't even know how to write a simple loop.
By only answering your question, what you need in your main function is:
for i in range(0,number+1):
if (breakdown(i)) == i:
print(str(i)+ " is super")
import math
def get(n):
for i in range(n):
l1 = list(str(i))
v = 0
for j in l1:
v += math.factorial(int(j))
if v == i:
print(i)
This will print all the super numbers under n.
>>> get(400000)
1
2
145
40585
I dont know how efficient the code is but it does produce the desired result :
def facto():
minr=int(input('enter the minimum range :')) #asking minimum range
maxr=int(input('enter the range maximum range :')) #asking maximum range
i=minr
while i <= maxr :
l2=[]
k=str(i)
k=list(k) #if i=[1,4,5]
for n in k: #taking each element
fact=1
while int(n) > 0: #finding factorial of each element
n=int(n)
fact=fact*n
n=n-1
l2.append(fact) #keeping factorial of each element eg : [1,24,120]
total=sum(l2) # taking the sum of l2 list eg 1+24+120 = 145
if total==i: #checking if sum is equal to the present value of i.145=145
print(total) # if sum = present value of i than print the number
i=int(i)
i=i+1
facto()
input : minr =0 , maxr=99999
output :
1
2
145
40585

Getting wrong sum in program to condense a number to a single digit by adding the digits recursively in Python 2.7

Why am I getting the sum as 8 instead of 9 here, when I give the input as 12345678 ?
This is my code :
def single_digit(a):
n=a
sum=0
while(n>0):
r=n%10
sum+=r
n=n/10
while sum>10:
single_digit(a)
return sum
a=input("\nEnter a number : ")
val=single_digit(a)
print"The number condensed to a single digit = ",val
This would result in an infinite loop. The value of sum never changes during the execution of the inner while loop and hence the while sum > 10: loop never terminates, because once sum crosses 10 you are in no way modifying it. In other words, there is no way for the control to come out of loop once sum crosses 10.
I would write the function as follows
def single_digit(a):
# Already in the simplest form. Nothing to do
if a < 10:
return a
num = a
sum_of_digits = 0
# Compute sum of digits of the number
while num > 0:
remainder = num % 10
sum_of_digits += remainder
num = num // 10
# Further condese the output to bring it to simple form i.e. single digit
if sum_of_digits > 10:
return single_digit(sum_of_digits)
else:
return sum_of_digits
Another clean and concise way to write the same code, in my opinion would be
def single_digit(a):
sum_of_digits = sum(int(digit) for digit in str(a))
if sum_of_digits < 10:
return sum_of_digits
else:
return single_digit(sum_of_digits)
while sum>10:
single_digit(a)
You are computing the sum of digits of a then checking if the sum is a single digit and if its not, you're computing the sum of digit of the original number a again, where you should computing for the new sum.
while sum>10:
sum = single_digit(sum)
Also, if you want to go recursive, go full recursive:
def single_digit(a):
# now it also works for negative numbers too
if -10 < a < 10:
return a
n=a
sum=0
while(n>0):
r=n%10
sum+=r
n= n/10
return single_digit(sum)
# a=input("\nEnter a number : ")
a = 12345678
val=single_digit(a)
print("The number condensed to a single digit = ",val)
Naming variables is not easy, but using descriptive names makes life easier :)
def sum_of_digits(num):
""" Recursively add the digits of a positive integer until the sum
becomes a single digit. Return the sum. """
if num < 10: # base case
return num
num_copy = num
result = 0
while num_copy > 0:
remainder = num_copy % 10
result += remainder
num_copy //= 10
return sum_of_digits(result)
print(sum_of_digits(12345678))
It prints 9

How can I Keep the following program running until it becomes a single digit number?

I want to write a program that can calculate the sum of an integer as well as count its digits . It will keep doing this until it becomes a one digit number.
For example, if I input 453 then its sum will be 12 and digit 3.
Then it will calculate the sum of 12=1+2=3 it will keep doing this until it becomes one digit. I did the first part but i could not able to run it continuously using While . any help will be appreciated.
def main():
Sum = 0
m = 0
n = input("Please enter an interger: ")
numList = list(n)
count = len(numList)
for i in numList:
m = int(i)
Sum = m+Sum
print(Sum)
print(count)
main()
It is not the most efficient way, but it doesn't matter much here; to me, this is a problem to elegantly solve by recursion :)
def sum_digits(n):
n = str(n)
if int(n) < 10:
return n
else:
count = 0
for c in n:
count += int(c)
return sum_digits(count)
print sum_digits(123456789) # --> 9 # a string
A little harder to read:
def sum_digits2(n):
if n < 10:
return n
else:
return sum_digits2(sum(int(c) for c in str(n))) # this one returns an int
There are a couple of tricky things to watch out for. Hopefully this code gets you going in the right direction. You need to have a conditional for while on the number of digits remaining in your sum. The other thing is that you need to covert back and forth between strings and ints. I have fixed the while loop here, but the string <-> int problem remains. Good luck!
def main():
count = 9999
Sum = 0
m = 0
n = input("Please enter an integer: ")
numList = list(n)
while count > 1:
count = len(numList)
for i in numList:
m = int(i)
Sum = m+Sum
print(Sum)
print(count)
# The following needs to be filled in.
numlist = ???
main()
You can do this without repeated string parsing:
import math
x = 105 # or get from int(input(...))
count = 1 + int(math.log10(x))
while x >= 10:
sum = 0
for i in xrange(count):
sum += x % 10
x /= 10
x = sum
At the end, x will be a single-digit number as described, and count is the number of original digits.
I would like to give credit to this stackoverflow question for a succinct way to sum up digits of a number, and the answers above for giving you some insight to the solution.
Here is the code I wrote, with functions and all. Ideally you should be able to reuse functions, and here the function digit_sum(input_number) is being used over and over until the size of the return value (ie: length, if sum_of_digits is read as a string) is 1. Now you can use the while loop to keep checking till the size is what you want, and then abort.
def digit_sum(input_number):
return sum(int(digit) for digit in str(input_number))
input_number = input("Please enter a number: ")
sum_of_digits = digit_sum(input_number)
while(len(str(sum_of_digits)) > 1):
sum_of_digits = digit_sum(input_number)
output = 'Sum of digits of ' + str(input_number) + ' is ' + str(sum_of_digits)
print output
input_number = sum_of_digits
this is using recursive functions
def sumo(n):
sumof = 0
while n > 0:
r = n%10 #last digit
n = n/10 # quotient
sumof += r #add to sum
if sumof/10 == 0: # if no of digits in sum is only 1, then return
return sumof
elif sumof/10 > 0: #else call the function on the sumof
sumo(sumof)
Probably the first temptation would be to write
while x > 9:
x = sum(map(int, str(x)))
that literally means "until there is only one digit replace x by the sum of its digits".
From a performance point of view however one should note that computing the digits of a number is a complex operation because Python (and computers in general) store numbers in binary form and each digit in theory requires a modulo 10 operation to be extracted.
Thus if the input is not a string to begin with you can reduce the number of computations noting that if we're interested in the final sum (and not in the result of intermediate passes) it doesn't really matter the order in which the digits are summed, therefore one could compute the result directly, without converting the number to string first and at each "pass"
while x > 9:
x = x // 10 + x % 10
this costs, from a mathematical point of view, about the same of just converting a number to string.
Moreover instead of working out just one digit however one could also works in bigger chunks, still using maths and not doing the conversion to string, for example with
while x > 99999999:
x = x // 100000000 + x % 100000000
while x > 9999:
x = x // 10000 + x % 10000
while x > 99:
x = x // 100 + x % 100
while x > 9:
x = x // 10 + x % 10
The first loop works 8 digits at a time, the second 4 at a time, the third two and the last works one digit at a time. Also it could make sense to convert the intermediate levels to if instead of while because most often after processing n digits at a time the result will have n or less digits, leaving while loops only for first and last phases.
Note that however the computation at this point is so fast that Python general overhead becomes the most important part and thus not much more can be gained.
You could define a function to find the sum and keep updating the argument to be the most recent sum until you hit one digit.
def splitSum(num):
Sum = 0
for i in str(num):
m = int(i)
Sum = Sum + m
return str(Sum)
n = input("Please enter an integer: ")
count = 0
while count != 1:
Sum = splitSum(n)
count = len(Sum)
print(Sum)
print(count)
n = Sum

Categories