Trying to write a piece of code that will sum the digits of a number. Also I should add that I want the program to keep summing the digits until the sum is only 1 digit.
For example, if you start with 1969, it should first add 1+9+6+9 to get 25. Since the value 25 has more than a single digit, it should repeat the operation to obtain 7 as a final answer.
Was just wondering how I could pull this off and possibly make it recursive as well. This is what I have so far
def sum_digits3(n):
r = 0
while n:
r, n = r + n % 10, n // 10
return r
Convert back and forth between strings and ints, make use of sum().
>>> def foo(n):
n = str(n)
if len(n) == 1:
return int(n)
return foo(sum(int(c) for c in n))
>>> foo(1969)
7
>>>
def foo(n):
n = str(n)
if len(n) == 1:
return int(n)
return foo(sum(int(c) for c in n))
It is as simple as involving explicitly the recursion.
def sum_digits3(n):
r = 0
while n:
r, n = r + n % 10, n // 10
if len(str(r))>1:
return sum_digits3(r)
return r
But i must admit that i am going to read the links given by suspicious dog. And the answer of wwii is smarter than mine.
Related
While practicing recursion I came across a question to reverse an integer using recursion. I tried to do the question without converting the integer into a string.
I was able to solve the question partially but the output would always come without any of the zeroes from the original input. Below is the code I came up with:
def reverseNumber(n):
if (n//10) == 0:
return n
lastDigit = n%10
ans = reverseNumber(n//10)
nod = 0
for i in str(ans):
nod += 1
return (10**nod)*lastDigit + ans
Upon inspection I could see that this was happening because when lastDigit is 0 it only returned the reversed integer from the recursive call i.e input 4230 will give 324.
But this also meant that all zeroes between the original input would also get removed as we went deeper in the recursive calls.
So please tell me how to modify this code so that zeroes in the original input are not removed while reversing.
You probably need just this:
def rev(n):
if n>0:
return str(n%10)+rev(n//10)
else:
return ''
reverseNumber should return an int and accept positive and negative numbers.
The simplest way to fix your code, without handling negative numbers, is:
def reverseNumber(n):
if n == 0:
return 0
lastDigit = n%10
n //= 10
return int(str(lastDigit) + str(reverseNumber(n))) if n else lastDigit
for test in (0, 123, 120):
print(test, reverseNumber(test))
Prints:
0 0
123 321
120 21
Yes! The reverse of 120 is 21 when you are dealing with int types as opposed to str types.
Another implementation that does handle negative numbers takes a whole different approach:
I have broken this out into two functions. Function rev is a generator function that assumes that it is being called with a positive, non-negative number and will recursively yield successive digits of the number in reverse. reverseNumber will join these numbers, convert to an int, adjust the sign and return the final result.
def reverseNumber(n):
def rev(n):
assert n >= 0
yield str(n % 10)
n //= 10
if n != 0:
yield from rev(n)
if n == 0: return 0 # special case
x = int(''.join(rev(abs(n))))
return x if n >= 0 else -x
tests = [0, 132, -132, 120]
for test in tests:
print(test, reverseNumber(test))
Prints:
0 0
132 231
-132 -231
120 21
For all non-negative n, when n < 10 it is a single digit and already the same as its reverse -
def reverse(n = 0):
if n < 10:
return str(n)
else
return str(n%10) + rev(n//10)
you can also try the following Python3 code. It will cover positive and negative integers to be reversed as integers - not as strings ...
x = int(input("What integer shall be reversed? "))
n = abs(x) # ... to handle negative integers
r = 0 # ... will hold the reversed int.
while n > 0: # Recursion part reversing int.
r = (r * 10) + (n % 10) # using '%' modulo
n = int(n / 10) # and a 'dirty way' to floor
if x < 0: # Turn result neg. if x was neg.
return (r * -1)
else:
return r # Keep result pos. if x was pos.
This approach will leave your zeros in the middle of the integer intact, though it will make any zero at the end of the initial number vanish - rightfully so as integers do not start with a zero. ;))
def digit_sum(n):
'''(int)->number
Returns the sum of all the digits in the given integer, n'''
if n<10:
return n
return n%10 + digit_sum(n//10)
def digital_root(n):
'''(int)->number
Returns the resulting sum of the digits in the given integer until it reaches a single digit number; via digit_sum'''
while n>9:
n=sum(digit_sum(n))
return n
Wrote the code for digit_sum and then used recursion to write digital_root. How would I go about this? Any help is appreciated!
Wikipedia lists a simple O(1) formula for the digital root:
def digit_root(n):
return (n - 1) % 9 + 1
This does not take into account an input less than 1, so you can modify as follows, with the assumption that the input is a whole number:
def digit_root(n):
return (n - 1) % 9 + 1 if n else 0
Examples:
>>> digit_root(1)
1
>>> digit_root(11)
2
>>> digit_root(235)
1
So the idea is that you have to use recursion for the last one as well? In that case, this should do the job:
def digital_root(n):
if n < 10:
return n
return digital_root(digit_sum(n))
Try this:
def num(n) :
sum = 0 #provided sum as 0
for i in str(n):
a = int(n) % 10 #taken variable a
sum = sum + a #put the sum.
n = n/10
print(sum)
if sum < 10:
print(str(sum) + "=this is a digital root")
else:
num(sum)
please try the following code:
def dgtl_rt(n):
return n%9 or n and 9
print(dgtl_rt(123))
def droot(a):
while a>=10:
b =int(a/10) #other digit(s)
c =a-(b*10) #the rightmost digit
a =b+c #add together
return a
I have not seen this solution anywhere, so I thought it would be nice to share, i discovered it myself! Just 1 looping structure.
{def MDR(n):
'''
this function returns multiplicative digital root.
'''
count, mdr = 0, n
while mdr > 9:
m, digitsMul = mdr, 1
while m:
m, md = divmod(m, 10)
digitsMul *= md
mdr = digitsMul
count += 1
return count, mdr}
def digit_sum(n):
if n==0 or n==1:
return n
else:
return n+digit_sum(n-1)
def digital_root(n):
if n<10:
return n
else:
return digit_sum((n // 10) + n % 10)
I am trying to use digit_sum to calculate the sum of digits of digital_root can someone help me please. I am trying to use a recursive function for digital_root.
Running the file in Python shell:
digital_root(1969)
This should calculate 1+9+6+9=25 then since 25 is greater than 10 it should then calculate the sum of its digits 2+5 so that the final answer is 7.
To get the last digit of a (positive integer) number you can calculate the modulo:
last_digit = n % 10
The remainder of the number (excluding the last place) is:
rest = (n - last_digit) / 10
This should in theory be enough to split a number and add the digits:
def sum_digits(n):
if n < 10:
return n
else:
last_digit = n % 10
rest = n // 10
# or using divmod (thanks #warvariuc):
# rest, last_digit = divmod(n, 10)
return last_digit + sum_digits(rest)
sum_digits(1969) # 25
If you want to apply this recursivly until you have a value smaller than 10 you just need to call this function as long as that condition is not fulfilled:
def sum_sum_digit(n):
sum_ = sum_digit(n)
if sum_ < 10:
return sum_
else:
return sum_sum_digit(sum_)
sum_sum_digit(1969) # 7
Just if you're interested another way to calculate the sum of the digits is by converting the number to a string and then adding each character of the string:
def sum_digit(n):
return sum(map(int, str(n)))
# or as generator expression:
# return sum(int(digit) for digit in str(n))
If you really require a recursive solution without using any loops (for, while) then you can always recurse again to ensure a single digit:
def digital_root(n):
if n < 10:
return n
a, b = divmod(n, 10)
b += digital_root(a)
return digital_root(b)
>>> digital_root(1969)
7
Or you could just not recurse at all:
def digital_root(n): # n > 0
return 1+(n-1)%9
>>> digital_root(1969)
7
try this...
digitSum = 0
solution = 0
S = raw_input()
S = list(map(int, S.split()))
#print S
for i in S:
digitSum += i
#print digitSum
singleDigit = len(str(digitSum)) == 1
if singleDigit == True: solution = digitSum
while singleDigit == False:
solution = sum( [ int(str(digitSum)[i]) for i in range( 0, len(str(digitSum))) ] )
digitSum = solution
singleDigit = len(str(solution)) == 1
print(solution)
for example def f(n):
and I wanna check whether the sum of the numbers within n equal to 100 whether it is in 1s, 2s, 3,s 4s, 5s and so on, depending on the length of n.
f(5050)
>>> True
This tests whether 5 + 0 + 5 + 0 == 100 and whether 50 + 50 ==100 and if any are true, it returns True.
Whether it tests in 1s, 2s 3s 4s and so on, depends on the length of the number. For example a number with a length of 5 can only be tested in 1s.
f(12345)
>>> False
This tests whether 1 + 2 + 3 + 4 + 5 == 100 and only that.
If the length of n was 15, it would test the digits in 1s, 3s and 5s.
and finally one more example:
f(25252525)
>>> True
This would test whether 2+5+2+5+2+5+2+5 == 100 and 25+25+25+25==100 and whether 2525+2525==100
So n, which has a length of 8 would be tested in 1s , 2s , and 4s. It cannot be tested with 3s and 5s because the length of all the digits within the number being summed up must be the same.
I hope I was able to explain what I'm after. Usually I would post what I've tried but I have no idea how to iterate over the digits of a number in such a way
The below approach uses generator to split the integer, and no integer <-> string conversion.
This will likely be the most efficient approach of the ones currently listed.
import math
# Define a generator that will split the integer v into chunks of length cl
# Note: This will return the chunks in "reversed" order.
# split(1234, 2) => [34, 12]
def split(v, cl):
while v:
(v,c) = divmod(v, 10**cl)
yield c
def f(v):
# Determine the number of digits in v
n = int(math.log10(v)) + 1
m = int(math.sqrt(v))
# Check all chunk lengths in [1, sqrt(v)]
for cl in range(m):
# Skip the chunk lengths that would result in unequal chunk sizes
if n % (cl+1): continue
# Create a generator, to split the value v into chunks of length cl
chunks = split(v, cl+1)
# If the sum of the chunks is 100, print a message and return True
if sum(chunks) == 100:
print("sum = 100 with chunklength: %d" % cl)
return True
# If we get here, none of the chunk lengths result in a sum of 100, return False
return False
print(f(5050)) # True (cl=2)
print("---")
print(f(12345)) # False
print("---")
print(f(25252525)) # True (cl=2)
print("---")
Output:
sum = 100 with chunklength: 2
True
---
False
---
sum = 100 with chunklength: 2
True
---
Without comments and debugging print:
import math
def split(v, cl):
while v:
(v,c) = divmod(v, 10**cl)
yield c
def f(v):
n = int(math.log10(v)) + 1
m = int(math.sqrt(v))
for cl in range(m):
if n % (cl+1): continue
if sum(split(v, cl+1)) == 100: return True
return False
print(f(5050)) # True
print(f(12345)) # False
print(f(25252525)) # True
I think this does the trick. Not sure though:
def f(n):
s = str(n)
l = len(s)
for n in (n for n in range(1, l + 1) if l % n == 0):
ints = [int(''.join(x)) for x in zip(*[iter(s)]*n)]
if sum(ints) == 100:
return True
return False
The zip thing comes from here. It's a little weird but it allows me to split the string up into n-length segments and then join it back together so I can apply an int mapping and then a sum reduction.
The generator just gets all positive divisors of l from 1 to l, both inclusive. There may be faster ways of doing it for large n using math.sqrt and divmod.
Assuming that the numbers are always positive integers, you can just divmod() them by 10 until you get to zero:
def int_iter(number):
while number > 0:
number, last_digit = divmod(number, 10)
yield last_digit
Note that gives you the digits in reverse order. That doesn't matter if you're just adding them together, though.
You can pass this around or use it in a for loop, like any other iterable:
digit_sum = sum(int_iter(number))
If you really need a sequence, just pass it to list():
digit_list = list(int_iter(number))
And if you need them in most-significant-first order, pass it to reversed():
digits_msf = reversed(list(int_iter(number)))
EDIT:
Whoops, I missed…about half of the question. Things are rather more complicated. You'll need a function to get all the factors of a number—I'm sure there are plenty, so I'll leave that as an excercise for you. Let's assume there's a function factors(number) that returns an iterable of all a number's factors (including nonprimes and 1, but not number itself). We'll also use the int_iter() from my original answer, an int_from_digits() that takes a list of digits and returns a single integer (sort of like the inverse of int_iter()), and something called grouper() from the itertools recipes.
from itertools import zip_longest
def int_from_digits(digits):
"Generate an integer from an iterable of single decimal digits"
# int_from_digits([4, 0, 2, 8, 9]) --> 40289
# int_from_digits([]) --> 0
number = 0
for digit in digits:
number *= 10
number += digit
return number
def grouper(iterable, n, fillvalue=None):
"Collect data into fixed-length chunks or blocks"
# grouper('ABCDEFG', 3, 'x') --> ABC DEF Gxx"
args = [iter(iterable)] * n
return zip_longest(*args, fillvalue=fillvalue)
def digit_subsequences(number):
digits = list(reversed(list(int_iter(number))))
for factor in factors(number):
for digit_grouping in grouper(digits, factor):
yield int_from_digits(digit_grouping)
Finally, armed with all these tools (or rather, one tool and its dependencies), we can perform your check with a simple comprehension and a call to any():
any(digit_subsequence == 100 for digit_subsequence in digit_subsequences(number))
One possible way, separated into functions for each logical step :
Get factors of n :
def get_factors(n):
return set(reduce(list.__add__,
([i, n//i] for i in range(1, int(n**0.5) + 1) if n % i == 0)))
For each l factor of n, split str(n) into chunks of length l :
def get_chunks(str_n, chunk_size):
total_size = len(str_n)
return [int(str_n[i:i+chunk_size]) for i in range(0, total_size, chunk_size)]
Check if sum of chunks in step 2 equals 100.
def f(n):
factors = get_factors(n)
for l in factors:
if sum(get_chunks(str(n), l)) == 100:
return True
return False
def factors(num):
yield 1
for i in range(2, num - 1):
if num % i == 0:
yield i
def pieces(string, sz):
for i in range(0, len(string), sz):
yield string[i:i+sz]
def check_sum(string):
for f in factors(len(string)):
pcs = pieces(string, f)
if sum([int(x) for x in pcs]) == 100:
print 'True'
return
print 'False'
>>> check_sum('5050')
True
>>> check_sum('25252525')
True
>>> check_sum('12345')
False
import sys
def keepsumming(number):
numberlist = []
for digit in str(number):
numberlist.append(int(digit))
total = reduce(add, numberlist)
if total > 9:
keepsumming(total)
if total <= 9:
return total
def add(x,y):
return x+y
keepsumming(sys.argv[1])
I want to create a function that adds the individual digits of any number, and to keep summing digits until the result is only one digit. (e.g. 1048576 = 1+0+4+8+5+7+6 = 31 = 3+1 = 4). The function seems to work in some laces but not in others. for example:
$python csp39.py 29
returns None, but:
$python csp39.py 30
returns 3, as it should...
Any help would be appreciated!
As others have mentioned, the problem seems to be with the part
if total > 9:
keepsumming(total) # you need return here!
Just for completeness, I want to present you some examples how this task could be solved a bit more elegantly (if you are interested). The first also uses strings:
while number >= 10:
number = sum(int(c) for c in str(number))
The second uses modulo so that no string operations are needed at all (which should be quite a lot faster):
while number >= 10:
total = 0
while number:
number, digit = divmod(number, 10)
total += digit
number = total
You can also use an iterator if you want to do different things with the digits:
def digits(number, base = 10):
while number:
yield number % base
number //= base
number = 12345
# sum digits
print sum(digits(number))
# multiply digits
from operator import mul
print reduce(mul, digits(number), 1)
This last one is very nice and idiomatic Python, IMHO. You can use it to implement your original function:
def keepsumming(number, base = 10):
if number < base:
return number
return keepsumming(sum(digits(number, base)), base)
Or iteratively:
def keepsumming(number, base = 10):
while number >= base:
number = sum(digits(number, base))
UPDATE: Thanks to Karl Knechtel for the hint that this actually is a very trivial problem. It can be solved in one line if the underlying mathematics are exploited properly:
def keepsumming(number, base = 10):
return 1 + (number - 1) % (b - 1)
There's a very simple solution:
while number >= 10:
number = sum(divmod(number, 10))
I am fairly sure you need to change
if total > 9:
keepsumming(total)
into
if total > 9:
return keepsumming(total)
As with most recursive algorithms, you need to pass results down through returning the next call.
and what about simply converting to string and summing?
res = 1234567
while len(str(res)) > 1 :
res = sum(int(val) for val in str(res))
return res
Thats's what I use to do :)
Here is a clean tail-recursive example with code that is designed to be easy to understand:
def keepsumming(n):
'Recursively sum digits until a single digit remains: 881 -> 17 -> 8'
return n if n < 10 else keepsumming(sum(map(int, str(n))))
Here you go:
>>> sumdig = (lambda recurse: (lambda fix: fix(lambda n: sum(int(c) for c in str(n)))) (recurse(lambda f, g: (lambda x: (lambda d, lg: d if d == lg else f(f,g)(d))(g(x),x)))))(lambda f: lambda x: f(f,x))
>>> sumdig(889977)
3
You are sure to get full, if not extra, credit for this solution.
Your code as currently written need to replace the recursive call to keepsumming(total) with return keepsumming(total); python does not automatically return the value of the last evaluated statement.
However, you should note that your code has redundancies.
for digit in str(number):
numberlist.append(int(digit))
total = reduce(add, numberlist)
should become
from operator import add
total = reduce(add, (int(digit) for digit in str(number)))
A code golf-able version that doesn't require a while loop, or recursion.
>>> import math
>>> (lambda x: sum(int((x * 10 ** -p) % 10) for p in range(math.ceil(math.log(x, 10)))))(1048576)
31
This is probably what I'd use though.
def sum_digits(number):
return sum(
int(number * (10 ** -place) % 10)
for place in range(math.ceil(math.log(number, 10)))
)
It's easier to see what's going on if you append to a list instead of summing the integer values.
def show_digits(number):
magnitude = int(math.log(number, 10))
forms = []
for digit_place in range(magnitude + 1):
form = number * (10 ** -digit_place) # force to one's place
forms.append(form)
return forms
>>> show_digits(1048576)
[1048576, 104857.6, 10485.76, 1048.576, 104.8576, 10.48576, 1.048576]
For keepsumming that takes a string:
def keepsumming(number):
return number if len(number) < 2 \
else keepsumming(str(sum(int(c) for c in number)))
For keepsumming that takes a number:
def keepsumming(number):
return number if number < 10 \
else keepsumming(sum(int(c) for c in str(number)))