Python Recursive Code (Beginner) - python-3.x

I'm currently trying to create a code that calculates how long a spaceship will take to travel a certain distance, every minute it will jump half the remaining distance. If there is a distance of less than 1 meter left, it will only take one more minute.
def space_time(d,t=0):
if d <= 1:
print("- It takes 1 minute to travel", d, "meters")
elif d > 1:
t = t + 1
return space_time(d / 2, t)
else:
t = t + 1
print("- ", t, "minutes to travel", d, "meters")
(space_time(10))
Output:
- It takes 1 minute to travel 0.625 meters
Process finished with exit code 0
I can see that my problem is the t = t + 1. My idea for this was every time the function is repeated it would add 1 to t which would signify 1 minute. But currently its not working. Any help would be greatly appreciated.

A problem is that it is impossible for the "elif d <= 1:" statement to get called, because the condition is exactly the same as the "if" condition above, which means this code will never be runned. You probably should change the "elif" to "if" if you want them both to be executed, or even better, merge them together
if d <= 1:
print("- It takes 1 minute to travel" , d, "meters")
elif d <= 1:
t = t + 1
return space_time(d/2)

There's a couple of problems here. For one, your 'elif' statement is checking the same condition as your if! I think you want 'greater than'.
Second, you are always setting t to 0 at the beginning, and not passing that back with the recursive loop. The original d is also not passed back.
Finally, I'm not sure what the else statement is supposed to be catching.
EDIT: If 0 < d < 1, then it takes one more minute. The last else captures this now.
def space_time(d_0,d=None,t=0):
if d is None:
d = d_0
if d <= 0:
print("- It takes", t, "minutes to travel" , d_0, "meters")
elif d > 1:
t = t + 1
return space_time(d_0,d/2,t)
else:
print("- It takes", t + 1, "minutes to travel" , d_0, "meters")
(space_time(10))
Output:
- It takes 5 minutes to travel 10 meters

Related

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.

Cant figure out conditionals

I'm working on a 30 day of code challenge and passed 5/8 tests on my code and can't figure out the reason it keeps failing
The parameters are that
if N is odd print weird,
if N is even and in the range of 2-5 print not weird
if N is even and in the range of 6-20 print weird
if N is even and greater than 20 print not weird
N = int(input())
if N % 2 == 0 and range(2-5):
print("Not Weird")
elif N % 2 == 0 and range(6-20):
print("Weird")
elif N % 2 == 0 and N > 20:
print("Not Weird")
elif N % 2 == 1 :
print("Weird")
if N % 2 == 0 and range(2-5):
does not do what you think, it should instead be something like:
if N % 2 == 0 and N in range(2, 6):
Specifically:
each sub-condition (on either side of your 'and') should be complete.
range, in your example, was range(-3) since that's what 2-5 gives.
the range is half open, meaning it includes the start but excludes the end.
1) The function range with defined begging and end is a function that takes 2 parameters as argument. Therefore I'd recommend you to use it as range(x,y) instead of range(x-y).
If you use it like range(2-5), you're actually asking for range(-3). When used with only 1 arg, the function range will give you a list of int from 0 up to the input arg.
Regarded that there is no integer greater than 0 and less than -3, then you're getting an empty list.
2) Also, notice that the upper limit is not inclusive:
>>> for i in range(2,5):
... print(i)
...
2
3
4
so you might consider to use range(2,6) for the first case, range(6,21) for the second case and so on and so forth..
To expand on #paxdiablo's answer, you can also use the step argument of range to test for even numbers:
if N in range(2, 6, 2):

Why isn't this function entering the while loop?

def millerRabin(toTest = 3, accuracy = 5):
# Return true if toTest is prime
################################
# Find how many times toTest can be halved
print(toTest)
under = toTest - 1
loopTracker = 0
while under % 2 == 0:
print('Before halving')
# Keep halving, and keep track until hit we can no longer divide in half
under = under // 2
print('After Halving: ', under)
loopTracker += 1
print("looped")
print(loopTracker)
print(millerRabin(toTest = 144000))
The first portion of the Miller-Rabin is to track how many times the number to be tested can be halved. But, I can't figure out why the program is not entering the while loop and outputting some of the print statements.
When you define under, you're subtracting 1. This creates 143999 to test, which is not divisible by 2 evenly. So it fails your while condition and never enters the loop.

How can I count and display my recursive steps in Python?

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.

Resources