Element-wise manipulation of a two dimensional list in python - string

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.

Related

Why does my solution to problem 3 of the CodeJam 2020 Qualification Round not work?

I would like to receive help in understanding why my solution to Problem 3 of the Google CodeJam 2020 Qualifier does not work.
Link to problem: https://codingcompetitions.withgoogle.com/codejam/round/000000000019fd27/000000000020bdf9
My solution:
High-level overview:
take input
figure out if the given input is impossible by sorting according to start times and then checking if more than 2 subsequent activities are 'active' at once (which is impossible)
if it is, output accordingly; if it isn't, proceed with the procedure below
arbitrarily assign the first person: in my solution I choose Cameron (C).
next, since we know that a solution exists, and the array I iterate through is sorted according to start times, if the very next activity interval (chronologically) overlaps in its duration with the current, assign it to the person who is not currently busy. This is purely because a solution exists, and it clearly cannot be the current person, so it must be the other.
moreover, if the very next activity interval (chronologically) does not overlap with the current activity, then assign it to the person who is currently busy (because he will not be busy for the next activity)
in addition, quoted directly from the problem's official analysis: "If an assignment is possible, there cannot be any set of three activities that pairwise overlap, so by the contrapositive of the the previous argument, we will be able to assign the activity to at least one of Jamie or Cameron at every step."
At this moment, I believe that these arguments suffice to show that my logic is valid, although my code evidently does not always produce the correct answer. I would greatly appreciate any help on this, since I have spent hours trying to debug, un-reason, or find a counter-example to my code to no avail. I have included my code, for reference, below.
Code:
for p in range(int(input())):
s = int(input())
l = []
for i in range(s):
l.append(list(map(int, list(input().split()))))
unsort = l.copy()
l = sorted(l, key=lambda tup: (tup[0],tup[1]))
enumerated = list(enumerate(unsort))
enumerated.sort(key=lambda x: x[1][0])
impossible = False
endings = sorted([(x[1], False) for x in unsort])
startings = sorted([(x[0], True) for x in unsort])
total = sorted(endings + startings, key=lambda tup: (tup[0], tup[1]))
size = 0
for i in total:
if i[1] == True:
size += 1
else:
size -= 1
if size > 2:
impossible = True
def overlap(a,b):
if not max(a[0], b[0]) >= min(a[1], b[1]):
return True
else:
return False
ans = "C"
def opp(a):
if a == "C":
return "J"
else:
return "C"
if impossible == True:
print("Case #" + str(p+1) + ": " + "IMPOSSIBLE")
else:
for i in range(0, s-1):
if overlap(l[i], l[i+1]) == True:
ans = ans + opp(ans[len(ans)-1])
else:
ans = ans + opp(opp(ans[len(ans)-1]))
#the stuff below is to order the activity assignments according to input order
key_value = [(ans[i], l[i]) for i in range(s)]
fans = ""
for i in range(s):
for j in range(s):
if enumerated[j][0] == i:
fans = fans + key_value[j][0]
print("Case #" + str(p + 1) + ": " + fans)

Difference between Python 3.x and Python 2.x in while loop

I have this piece of code, which I had written a few weeks ago. Initially I wrote it for Python 2.7 and it works very well, but I decided some time ago to just abandon it, and move to Python 3.7. Can anyone explain me why this while loop is infnite and doesn't want to fullfill those conditions?
In Python 2.7 this code allows me to browse between my files of data, and those amateurs tricks in my code allows me to handle obstackles such as changing hour after 60 minutes or date after 24 hours. Still have no idea how to convert it to Python 3.
# Input variables
h = "Arctic"
u = 'Denver'
p = 'Patagonia'
Station = input('Enter a station name (Arctic = h, Denver = u, Patagonia = p): ')
Date = input('Enter date time (yyyymmdd): ')
Date_end = input('Enter end date time (yyyymmdd): ')
Start_time_hours = int(input('Enter start time (hh): '))
Start_time_minutes = int(input('Enter start time (mm): '))
End_time_hours = int(input('Enter end time (hh): '))
End_time_minutes = int(input('Enter end time (mm): '))
Save_Print_SavPrin = input('Press s = Save, p = Plot: ')
while Start_time_hours == Start_time_hours and Start_time_minutes == Start_time_minutes and Date == Date:
Start_time_hours += (Start_time_minutes / 60)
Start_time_minutes %= 60
str(Start_time_minutes)
str(Start_time_hours)
str(End_time_minutes)
str(End_time_hours)
Start_time_hours_format = '{:02}'.format(Start_time_hours)
Start_time_minutes_format = '{:02}'.format(Start_time_minutes)
End_time_hours_format = '{:02}'.format(End_time_hours)
End_time_minutes_format = '{:02}'.format(End_time_minutes)
int(Start_time_minutes)
Start_time_minutes += 5
if Save_Print_SavPrin == "p":
print("Showing figures...")
print ("Succesful!")
if Start_time_hours_format == End_time_hours_format and Start_time_minutes_format == End_time_minutes_format and Date == Date_end:
print (Start_time_hours_format, Start_time_minutes_format, End_time_hours_format, End_time_minutes_format)
break
First, your loop condition is an infinite loop, because you're comparing variables to ... themselves. So you can replace by while True: (valable for both python versions)
Now the problematic code is this:
Start_time_hours += (Start_time_minutes / 60)
in python 3, / 60 performs floating point division, even between integer operands. The result is that now Start_time_hours is a float, and can never be equal to End_time_hours, which is an integer (the if Start_time_hours_format == End_time_hours_format test always fails, specially because you're converting both to string).
The fix (works for both versions) is to force integer division:
Start_time_hours += (Start_time_minutes // 60)
Aside, doing str(something) alone on a line isn't going to turn that something into a string unless you assign it back to something. You can remove all those statements, as they're useless anyway.

Python Recursive Code (Beginner)

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

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.

Averaging a list from a file and also find the min and max rate of change between each index Python

We received a file called USPopulation.txt, with instructions that basically say line 1 in the file is the year 1950 and the last line being 1990. we needed to store the data in a list and do 3 things with said data.
Find the average(somewhat easy i think i have this down)
Find the maximum rate of change in any 1 year
Find the minimum rate of change in any 1 year
The Average of the numbers code taken from a past program
list_of_numbers = []
with open('USPopulation.txt') as f:
for line in f:
if line.strip():
list_of_numbers.append(int(line.strip()))
print('Total ',len(list_of_numbers))
print('Average ',1.0 * sum(list_of_numbers) / len(list_of_numbers))
I need to combine the other elements and have no idea how any help would be great
The rate of change is the difference between two subsequent values in the list. To get that value, you basically need to store the previous value and compare it to the current one.
One way of doing this would be to simply loop through your list, and collect those values:
previous = None:
ratesOfChange = []
for num in list_of_numbers:
if previous:
ratesOfChange.append(abs(num - previous))
previous = num
Getting the maximum and minimum is then as easy as calling max() and min() on the ratesOfChange list.
Of course to improve this a bit, you might want to consider collecting those values while parsing the file already (so you save the second loop through the list). And you could even note down the minimum and maximum at the same time to save another loop through it (both max and min will loop over the list).
if USPopulation.txt is like
1950=10000
1951=10005
1952=10030
then by converting the above lines into dictionary so that one can access each year and its corresponding population
file1 = open("USPopulation.txt", "r+")
years_dict = dict()
arr = []
class population:
def __init__(self):<br>
self.average = 0
self.maximum = 0
self.minimum = 0
def average_method(self):
try:
for line in file1.readlines():
value1 = line.split('=', 1)
years_dict[value1[0]] = int(value1[1])
length_of_dictionary = len(years_dict.keys())
for values in years_dict.values():
self.average = self.average + values
self.average = (1.0 * self.average / length_of_dictionary)
except:
print "not able to read the lines from the file"
def maximum_method(self):
try:
i = 0
for year in range(1950, 1952):
arr.insert(i, (years_dict[str(year + 1)] - years_dict[str(year)]))
i = i + 1
self.minimum = min(arr)
self.maximum = max(arr)
except:
print "not able to insert the element"
obj = population()
obj.average_method()
obj.maximum_method()
print "Average of population: " + str(obj.average)
print "maximum rate of change: " + str(obj.maximum)
print "minimum rate of change: " + str(obj.minimum)

Resources