Why doesn't this digital root function work? [closed] - python

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 4 years ago.
Improve this question
I'm doing a challenge on codewars, and I'm supposed to write a digital root function in Python. I can't figure out why it's not working. This is my first attempt at recursion. I would really like to wrap my head around this.
def digital_root(num):
#Check to see if num has more than one digit
if num > 9:
x = 0
z = 1
#Create an array of the digits in num
digits = [int(d) for d in str(num)]
#Convert string elements in digits[] to ints
for n in digits:
digits[x] = int(x)
x = x + 1
#Add each element in digits[] to digits[0]
for n in digits:
digits[0] = digits[0] + digits[z]
#If digits[0] has more than one digit, then run digital_root with digits[0] in the parameters
if digits[0] > 9:
digital_root(digits[0])
else:
return digits[0]
else:
return num
digital_root(15)
>> Program finished with exit code 0

There are a lot of things wrong with your function. Let's go down the list.
#Convert string elements in digits[] to ints
for n in digits:
digits[x] = int(x)
x = x + 1
This section is intended to convert the elements of digits into ints, but the elements of digits are already ints. The earlier list comprehension already produced ints:
digits = [int(d) for d in str(num)]
# ^^^^^^
The whole section is unnecessary. It's not even filling digits with the right ints; instead of calling int on the elements of digits, it calls int on the indices. Also, the loop makes no use of the loop variable n.
for n in digits:
digits[0] = digits[0] + digits[z]
This loop attempts to add all the digits together. However, z is never incremented, so this adds digits[1] to digits[0] every time. Also, even if the loop was changed to increment z, it would most likely go too far and run off the end of the list; z starts at 1, and the loop performs one iteration for each element of digits, so by the last iteration, z would be past the end of the list. Also, again, the n variable is unused.
Using digits[0] as a place to hold the sum muddles up the meaning of the digits array during the loop. It'd be better to use a separate variable (and doing so would avoid needing to start z at 1), but since Python already has a sum function, it'd be even simpler to just use sum.
#If digits[0] has more than one digit, then run digital_root with digits[0] in the parameters
if digits[0] > 9:
digital_root(digits[0])
else:
return digits[0]
This is inside the above loop, but it doesn't look like it's supposed to be; it looks like it was intended to run after digits[0] contains the sum. If so, it should be dedented (delete 4 spaces from each line). Also, since there's no return on the recursive call, the return value of the recursive call is discarded.
A corrected version of your function could look like
def digital_root(num):
if num > 9:
digits = [int(d) for d in str(num)]
total = 0
for n in digits:
total += n
if total > 9:
return digital_root(total)
else:
return total
else:
return num
A simpler solution to the challenge, taking advantage of sum, would be
def digital_root(num):
while num > 9:
num = sum(map(int, str(num)))
return num
or, keeping it recursive,
def digital_root(num):
if num < 10:
return num
return digital_root(sum(map(int, str(num))))

Related

How to ask for 20 numbers in python and, then, print the sum of positives and quantities of negatives?

The problem seems very simple but I'm cracking my head over it. It's just an algorithm exercise. This is what I have so far:
positivesum = 0
negativeqt = 0
value = int(input(("Enter the numbers: ")))
for _ in range(20):
value
if value > 0:
positivesum = positivesum + value
print("The sum of positives is ", positivesum)`
Also, if someone could translate the same exercise in Javascript, I would appreciate it.
Something like this?
Python:
sum_positive_number = 0
negative_number_quantities = 0
numbers = 20
for i in range(numbers):
number_input = int(input(f'Enter number #{i+1}: '))
if number_input > 0:
sum_positive_number += number_input
elif number_input < 0:
negative_number_quantities += 1
print('Sum of positive numbers: ', sum_positive_number)
print('Quantities of negative numbers: ', negative_number_quantities)
int_list = [int(inp) for inp in input("Enter 20 numbers: ").split()]
pos_sum = sum(num for num in int_list if num > 0)
neg_quantity = len([num for num in int_list if num < 0])
print(f"{pos_sum=} {neg_quantity=}")
How It Works
int_list is something called a list comprehension. When prompted with the input, a user is able to input the 20 numbers, with spaces in between the different numbers due to the call to split(). split() by default will split by a white space character. split() will return an iterable list, so we iterate over that list with for inp in …. int(inp) will convert each of the numbers from type str to type int. input() returns a string, so this is needed to do number operations
pos_sum calls the sum built in and passes it a generator expression. It iterates over the list resulting from all of the operations done in int_list and only looks for the numbers that are greater than 0. It will add these up, giving us our sum.
neg_quantity calls the len built in and passes in an iterable list to len, constructed through a list comprehension. The resulting list from the comprehension will contain all numbers from int_list less than 0, and len will return the length of that list, giving us our quantity of negatives
nums = list(map(int, input('Enter the numbers: ').split()))
pos = sum(num for num in nums if num > 0)
neg = len(num for num in nums if num < 0)
print(pos, neg)
split the input separated by whitespace by default and map each substring, i.e. number, to its int. list initializes a list to store the result of of map.
Notice that sum takes iterable. Expressions in the form of num for num in nums if num > 0 are generators. A generator yields a result one by one according to the condition until it terminates. When a generator expression is passed into a function as an argument, the result is passed as a tuple which is iterable. Therefore pos gives you the sum of all positive numbers in the list. Compared to a list comprehension, generators do not demand extra space and once the result is passed in, python can automatically collect the garbage for you.
This answer explains a little bit more about generator expressions and provides another way to get and store the input.
sum(iterable,/,start=0)
len(s)
map(function,iterable,...)
Your issue is that you put the input statement in the wrong place:
positivesum = 0
negativeqt = 0
for _ in range(20):
value = int(input(("Enter the numbers: ")))
if value > 0:
positivesum += value
else if value < 0:
negativeqt += 1
If you only ask for one input then the user can only give you one number. Since you want twenty numbers, you need to put the input inside your for-loop so you get a value every time you need a value.
With regard to the difference between calculating positivesum and negativeqt, you're looking for the total of the positive terms so you need to add them together whereas you only want the quantity of negative terms so we increment once every time we see one.
positive = 0
negative = 0
for i in range(-10 , 10):
print(i)
if i >= 0:
positive += i
elif i <= 0:
negative += 1
print(positive)
print(negative)

alternative to if else python

Ok i wrote this in python then rewrote because i don't like if else statements.
the first version worked perfectly. my second one failed and ended up taking more lines than my first version. my question is, am i just stupid? is there a better way to do this or should i just accept the need for if else statement?
sorry for the code dump, i am going mad
first attempt
#number we are starting with
num = 1
#what we are going to apply equation loop to
result = num
#how many times goes through equation loop before reaching 1
count = 0
# list of numbers used in equation loop
num_in_loop = [result]
#end equation loop function.
running = True
# equation loop
def eqation_loop(running, num_in_loop, count, num, result):
while running == True:
if (result % 2) == 0:
result = result /2
count +=1
num_in_loop.append(result)
elif result == 1.0:
print(num, "took", count ," loops to get to 1: numbers in loop = ", num_in_loop, file=open('3x+1/result.txt','a'))
num +=1
print(num)
result = num
num_in_loop = [result]
count = 0
elif num == 100:
running = False
elif (result % 2) != 0:
result = result * 3 + 1
count +=1
num_in_loop.append(result)
eqation_loop(running, num_in_loop, count, num, result)
second attempt:
#number we are starting with
num = 1
#what we are going to apply equation loop to
result = num
#how many times goes through equation loop before reaching 1
count = 0
# list of numbers used in equation loop
num_in_loop = [result]
limit = int(input("range you want to try: " ))
def update_var(num_in_loop,result,count):
count +=1
num_in_loop.append(result)
return equation_loop(limit,num, result)
def reset_var(num_in_loop, count, limit,num, result):
print(num, "took", count ," loops to get to 1: numbers in loop = ", num_in_loop, file=open('3x+1/test.txt','a'))
num +=1
result = num
num_in_loop = [result]
count = 0
return equation_loop(limit,num, result)
def equation_loop(limit,num, result):
if num == limit:
return
elif result == 1:
return reset_var(num_in_loop, count, limit,num, result)
elif (result % 2) == 0:
result = result /2
return update_var(num_in_loop,result,count)
elif (result % 2) != 0:
result = result *3 +1
return update_var(num_in_loop,result,count)
equation_loop(limit,num, result)
You can't write this without any if/else statements (okay maybe if you really know what you're doing you technically can by severely abusing while, but you shouldn't), but here's a simplified-down version that hopefully contains some useful examples of how to make your code easier to write (and read!):
def equation_loop(num: int) -> list[int]:
"""
Repeatedly applies the magic equation trying to
reach 1.0, starting with num. Returns all the results.
"""
nums = [num]
while True:
if num == 1:
return nums
if num % 2:
num = num * 3 + 1
else:
num = num // 2
nums.append(num)
for num in range(1, 100):
results = equation_loop(num)
print(f"{num} took {len(results)} loops to get to 1: {results}")
A key thing here is that you don't need so many variables! A single loop only needs its starting point (num) and only needs to return the list of results (from which you can get the count, since it'll be the length of the list). Reducing the number of redundant variables eliminates a lot of unnecessary lines of code that are just copying state back and forth. Passing a value like running = True is unnecessary when it will always be True until it's time to end the loop -- instead just use while True: and return or break when you're done.
The big takeaway is that if you have two variables that always have the same value (or even two values that are always related in exactly the same way, like a list and its length), you probably just need one of them.
You can also simplify the code by separating the two nested loops -- for a given num you want to loop until the number reaches 1, so that's one loop. You also want to loop over all the nums up to 99 (it took me a while to even figure out that that's what the code was doing; I had to run it and look at the output to see that some of those extra pieces of state were serving to implement nested loops inside a single loop). Doing those in two different loops makes it easy, and you can put one of them in a nice neat function (I used your equation_loop name for that, although it does less work than your original version does) that takes the starting num and returns the list of results for that starting point. That simple function can then be called in an even simpler for loop that iterates through the nums and prints the results for each one.
Note that I kept everything as ints by using int division (//) -- testing floats for exact equality is often dangerous because floating point numbers aren't exactly precise! Your equation is always operating with integer values (because you only divide by two if it's an even number) so it makes more sense to use int division and not even worry about floating point values.

Function to generate a palindrome

I have this following that I can't seem to solve correctly.
I have to write a function that takes a positive integer n as an input and checks if it is a palindrome (a number that's the same forward and backward). If it is, I have to return this number. If it isn't, I have to calculate the sum of the original number with the reversed number. This step is repeated until the result is a palindrome. This is the code I have so far:
x = input("Enter a positive integer: ")
def generate_palindrome(n):
if n == n[::-1]:
return n
else:
while n != n[::-1]:
r = n[::-1]
int(n) += int(r)
return n
generate_palindrome(x)
Of course this returns an error, since int(n) += int(r) is not possible. However, when not using int, it adds it as a string and that's also incorrect.
I'm not sure how far I'm off with the solution. How can I implement this correctly?
You are close. You just need another variable for the integer version of your string.Then just be clear which holds a string and which holds an integer:
def generate_palindrome(n):
if n == n[::-1]:
return n
else:
while n != n[::-1]: # n needs to be a string for this to work
r = int(n[::-1]) # r and s need to be numbers for correct addition
s = int(n)
n = str(r + s) # n needs to still be a string for the next loop iteration
return n
generate_palindrome("989")
# '989'
generate_palindrome("98")
# '8813200023188'
FWIW, I don't know that this is always guaranteed to return a reasonably sized number for every input. For example, I gave up on generate_palindrome("5798").

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