How can I count and display my recursive steps in Python? - python-3.x

I am trying to count how many times my program goes through my recursive statement and gives me my result. This is the code:
def days(amt):
day = 0
new = (amt*.05) + amt - 10
if amt == 0:
return 0
elif amt == '':
return
elif new >= 0 and new <= 1000:
day += 1
return days(new)
print("In {} days, you'll have {}".format(day,new))
So when you call the function days(100), it calculates that it takes 15 days to reach new amount which less than 0 or greater than 1000 (and then it stops bc it satisfies the second elif condition).
So I want my output to look like this In 15 days, you'll have -7.892....
My problem is no matter where I place the counter, it doesn't count.

To persist the count you need to either use some global variable or use a parameter to do the counting then return both the count and the amt:
def days(amt, day=1):
new = (amt * .05) + amt - 10
if amt == 0:
return day, 0
elif 0 <= new <= 1000:
return days(new, day + 1)
return day, new
Which gives you:
In [2]: print("In {} days, you'll have {}".format(*days(100)))
In 15 days, you'll have -7.89281794114
You cannot set day = 0 anywhere in the function as every call is going to reset it to 0. I also removes elif amt == '' as I cannot see how a function that takes an int/float should ever equal to an empty string.

Related

How do I fix sum of digits of a number code not entering an infinite loop?

I don't understand why it enters an infinite loop. I stated that: if a % 10 == 0: it should break the loop but it doesn't seem to do so. Could someone explain why this happens and why it is not correct and the solution. Thank you!
a = int(input())
total = 0
while a>0:
rest = a % 10
total += rest
if rest == 0:
break
print(total)
It is running for infinite times because of logical error. value of a is not decreasing.
you are checking for remainder, suppose value of a is 230. then at first iteration rest will be 0 and your output will be also 0 (correct sum will be 5).
correct code will be :-
a = int(input())
total = 0
while a>0:
rest = a % 10
total += rest
a=a//10
print(total)

Counting 9's in numbers from 1 to n

I'm trying to count all 9's in numbers from 1 to n, including repeating digits such as in 99. My code (python 3) works and returns the corrects answer for most cases except for very large numbers (like 20 digit numbers). Could someone help and let me know how this is possible?
Thanx.
def count_nines(n):
count = 0
num = [i for i in str(n)]
while len(num) > 0:
if len(num) == 1:
if num[0] == '9':
count += 1
else:
count += int(num[0]) * int(str(len(num)-1).ljust(len(num)-1, '0'))
if num[0] == '9':
count += int(''.join(num[1:]))+1
num.pop(0)
return count
The problem is in this expression:
int(str(len(num)-1).ljust(len(num)-1, '0'))
This works fine as long as str(len(num)-1) is one character, but when len(num) > 10, this is no longer the case, and then ljust will add fewer zeroes than needed. In fact, you always want to append len(num)-2 zeroes. So change this expression to:
int(str(len(num)-1) + '0' * (len(num)-2))
Simply:
def count_nines(n):
count = 0
for i in range(n+1):
if "9" in [*str(i)]:
count = count + str(i).count('9')
return count
sum((str(i).count('9') for i in range(1, n+1)))

Polydivisible Calculator Fails, Despite Previous Implementation Working

To begin, a definition:
A polydivisible number is an integer number where the first n digits of the number (from left to right) is perfectly divisible by n. For example, the integer 141 is polydivisible since:
1 % 1 == 0
14 % 2 == 0
141 % 3 == 0
I'm working on a recursive polydivisible checker, which, given a number, will check to see if that number is polydivisible, and if not, recursively check every other number after until it reaches a number that is polydivisible.
Unfortunately, my code doesn't work the way I want it to. Interestingly, when I input a number that is already polydivisible, it does its job and outputs that polydivisible number. The problem occurs when I input a non-polydivisible number, such as 13. The next polydivisible number should be 14, yet the program fails to output it. Instead, it gets stuck in an infinite loop until the memory runs out.
Here's the code I have:
def next_polydiv(num):
number = str(num)
if num >= 0:
i = 1
print(i)
while i <= len(number):
if int(number[:i]) % i == 0:
i += 1
print(i)
else:
i = 1
print(i)
num += 1
print(num)
else:
return num
else:
print("Number must be non-negative")
return None
I'm assuming the problem occurs in the else statement inside the while loop, where, if the number fails to be polydivisible, the program resets i to 0, and adds 1 to the original number so it can start checking the new number. However, like I explained, it doesn't work the way I want it to.
Any idea what might be wrong with the code, and how to make sure it stops and outputs the correct polydivisible number when it reaches one (like 14)?
(Also note that this checker is only supposed to accept non-negative numbers, hence the initial if conditional)
The mistake is that you are no updating number after incrementing num.
Here is working code:
def next_polydiv(num):
number = str(num)
if num >= 0:
i = 1
print(i)
while i <= len(number):
if int(number[:i]) % i == 0:
i += 1
print(i)
else:
i = 1
print(i)
num += 1
print(num)
number = str(num) # added line
else:
return num
else:
print("Number must be non-negative")
return None
I have a similar answer to #PranavaGande, the reason is I did not find any way to iterate an Int. Probably because there isn't one...Duh !!!
def is_polydivisible(n):
str_n = str(n)
list_2 = []
for i in range(len(str_n)):
list_2.append(len(str_n[:i+1]))
print(list_2)
list_1 = []
new_n = 0
for i in range(len(str_n)):
new_n = int(str_n[:i+1])
list_1.append(new_n)
print(list_1)
products_of_lists = []
for n1, n2 in zip(list_1, list_2):
products_of_lists.append(n1 % n2)
print(products_of_lists)
for val in products_of_lists:
if val != 0:
return False
return True
Now, I apologise for this many lines of code as it has to be smaller. However every integer has to be split individually and then divided by its index [Starting from 1 not 0]. Therefore I found it easier to list both of them and divide them index wise.
There is much shorter code than mine, however I hope this serves the purpose to find if the number is Polydivisible or Not. Of-Course you can tweak the code to find the values, where the quotient goes into decimals, returning a remainder which is Non-zero.

Element-wise manipulation of a two dimensional list in python

I am writing a script to find meeting time for three people. I manage to get their Free/Busy status encoding in a binary format with 0 being free and 1 being busy in increment of 30 minutes for the next three days. I grouped their status by day into a dictionary format as below.
print(date_schedule)
{'Monday, 2020-02-03': ['000000000000000000101101001110110000000000000000',
'000000000000000000001111011100001100000000000000',
'000000000000000011110100011000110000000000000000'],
'Tuesday, 2020-02-04': ['000000000000000000100010000000000000000000000000',
'000000000000000000001111001000110000000000000000',
'000000000000000011111000111100101000000000000000'],
'Wednesday, 2020-02-05': ['000000000000000000111000000000000000000000000000',
'000000000000000001001100110000000000000000000000',
'000000000000000000111100000001001000000000000000']}
Goal: Translate those 0 into a block of thirty minutes intervals.
For Example: 00:00----00:30
00:30----01:00
...
23:30----24:00
Attempted:
#Separate the code into a two dimensional list
schedule = date_free.values()
#Append the block to a new list.
free = []
for value in schedule:
for v in value:
for idx, time in enumerate(v):
if time == '0':
idx = idx/2
end = idx + 0.5
#5 slots, and two decimals
idx = '{:05.2f}'.format(idx).replace('.50','.30').replace('.',':')
end = '{:05.2f}'.format(end).replace('.50','.30').replace('.',':')
free.append((idx + '----' + end))
Problem: free has 372 elements and I don't know how to make it become a two-dimensional-list structure as it was before in schedule (because the number of 0 is different for each v). Is there a way to not creating a new list but directly apply the above logic element-wise to schedule?
Bonus question: I have not gotten there yet, but my next goal is to find the intersection of those 30 time block for each day as demonstrated in the random example below. If you have any suggestions, please let me know
print(date_time_final)
{'Monday, 2020-02-03': ['08:00----08:30','09:30----10:00','12:00----12:30'],
'Tuesday, 2020-02-04' : ['09:00----09:30','10:30----11:00','13:00----13:30','14:00----14:30']
'Wednesday, 2020-02-05' : ['07:00----07:30','14:30----15:00','15:00----15:30','19:00----19:30']}
Thank you in advance for your help!
Is something like this what you were looking for?
schedule = {'Monday, 2020-02-03': ['000000000000000000101101001110110000000000000000',
'000000000000000000001111011100001100000000000000',
'000000000000000011110100011000110000000000000000'],
'Tuesday, 2020-02-04': ['000000000000000000100010000000000000000000000000',
'000000000000000000001111001000110000000000000000',
'000000000000000011111000111100101000000000000000'],
'Wednesday, 2020-02-05': ['000000000000000000111000000000000000000000000000',
'000000000000000001001100110000000000000000000000',
'000000000000000000111100000001001000000000000000']}
combined = {}
for value in schedule:
day = {}
for v in schedule[value]:
for idx, time in enumerate(v):
idx = idx/2
end = idx + 0.5
#5 slots, and two decimals
idx = '{:05.2f}'.format(idx).replace('.50','.30').replace('.',':')
end = '{:05.2f}'.format(end).replace('.50','.30').replace('.',':')
if time == '0':
try: #Only assigns "True" if value does not yet exist and is not already False
if day[idx + '----' + end] == False:
pass
else:
day[idx + '----' + end] = True
except:
day[idx + '----' + end] = True
elif time == '1':
day[idx + '----' + end] = False
combined[value] = day
for day in combined:
print(day)
for time_slot in combined[day]:
print("Time slot %s is free = %s" % (time_slot, str(combined[day][time_slot])))
Instead of lists, I used dictionary format to sort by day and by time slot, maintaining every time slot on record, but giving them a boolean value to determine if its free or not. (True == free, False == busy)
That way you can do whatever you like with the output.

In binary search, why is my loop infinite?

I run a while loop with a function to check if a variable i is higher than the len of the list. I placed it there as a way to stop the loop, but it does not check it. Since it doesn't end on it's own I had to place an if condition inside that returns false.
def binarySearch(numberlist, number):
first = 0
last = len(numberlist)-1
found = False
i=0
while found == False or i <= len(numberlist):
i = i + 1
mid = (first + last) // 2
print(numberlist[mid])
if i > len(numberlist)+1:
return False
if mid < first or mid > last or mid < 0:
return False
if number == numberlist[mid] or number == numberlist[first] or number == numberlist[last] :
return True
elif number < numberlist[mid]:
last = mid
elif number > numberlist[mid]:
first = mid
return False
The error lies in the following lines.
elif number < numberlist[mid]:
last = mid
elif number > numberlist[mid]:
first = mid
Consider the case where we are looking for a number which is not in the list.
The pointers first, last and mid will eventually all converge to some index. In that case one of the two last conditions will be True, but since all three values are already equal, the pointers are not updated anymore and we enter an infinite loop.
To makes sure this does not happen, we must make sure the interval always decreases in size by setting first to mid + 1 or last to mid - 1, depending on the condition. We can then stop looping if first becomes greater than last.
def binary_search(numberlist, number):
first, last = 0, len(numberlist) - 1
while first <= last:
mid = (first + last) // 2
if numberlist[mid] == number:
return True
elif numberlist[mid] > number:
last = mid - 1
else:
first = mid + 1
return False

Resources