Spaces:
Runtime error
Runtime error
Sorting availability dict by how available people are to teach
Browse files- workshops.py +59 -35
workshops.py
CHANGED
@@ -63,17 +63,50 @@ def can_teach(person: str, slot: list, capacity: int) -> bool:
|
|
63 |
|
64 |
|
65 |
# Extracts relevant information from the df with availability and puts it into a useable format
|
66 |
-
def convert_df(df):
|
67 |
-
people = []
|
68 |
# Key: person's name
|
69 |
# Value: a list of their availability
|
70 |
availability = {}
|
71 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
72 |
for row in range(len(df)):
|
73 |
-
# TODO: make sure no people with the same name fill out the form
|
74 |
name = df.loc[row, NAME_COL]
|
|
|
|
|
|
|
|
|
|
|
75 |
|
76 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
77 |
if number == 1:
|
78 |
people.append(name)
|
79 |
|
@@ -82,12 +115,8 @@ def convert_df(df):
|
|
82 |
for i in range(number):
|
83 |
people.append(name)
|
84 |
|
85 |
-
curr_avail = df.loc[row, AVAIL_COL]
|
86 |
-
curr_avail = curr_avail.split(DELIMITER)
|
87 |
-
curr_avail = [elem.strip() for elem in curr_avail]
|
88 |
-
availability[name] = curr_avail
|
89 |
|
90 |
-
return people, availability
|
91 |
|
92 |
|
93 |
|
@@ -141,13 +170,12 @@ def find_all_schedules(people: list, availability: dict, schedule_obj: Schedule,
|
|
141 |
# Unchoose (remove that person from the timeslot)
|
142 |
schedule_obj.remove(person, time)
|
143 |
# NOTE: this will not generate a full timeslot, but could still lead to a good schedule
|
144 |
-
'''
|
145 |
else:
|
146 |
if len(people) == 1:
|
147 |
find_all_schedules([], availability, schedule_obj, capacity, schedules, max_timeslots_list, max_workshops_list)
|
148 |
else:
|
149 |
find_all_schedules(people[1:len(people)], availability, schedule_obj, capacity, schedules, max_timeslots_list, max_workshops_list)
|
150 |
-
|
151 |
|
152 |
return
|
153 |
|
@@ -242,7 +270,7 @@ def get_description_dict(df):
|
|
242 |
|
243 |
|
244 |
# Classifies schedules into two categories: complete and incomplete:
|
245 |
-
# Complete = everyone is teaching desired number of timeslots and each timeslot
|
246 |
# NOTE: I'm using "valid" instead of "complete" as a variable name so that I don't mix it up
|
247 |
# Incomplete = not complete
|
248 |
def classify_schedules(people: list, schedules: list, partial_names: list, total_timeslots: int, max_timeslots_filled: int) -> tuple:
|
@@ -345,43 +373,41 @@ def get_best_schedules(schedules: list, cutoff: str, max_workshops: int) -> list
|
|
345 |
# Big wrapper function that calls the other functions
|
346 |
def main(df, capacity:int, num_results: int, og_slots: list):
|
347 |
descrip_dict = get_description_dict(df)
|
348 |
-
|
349 |
-
# Convert the df with everyone's availability to a usable format
|
350 |
-
res = convert_df(df)
|
351 |
-
people = res[0]
|
352 |
-
availability = res[1]
|
353 |
-
|
354 |
-
# Sorts a dictionary by length of the values such that the
|
355 |
-
# key associated with the shortest value is first in the list {orders}
|
356 |
-
order = sorted(availability, key=lambda k: len(availability[k]))
|
357 |
-
|
358 |
-
# The idea is start with people who are the LEAST available to teach,
|
359 |
-
# then put the more available instructors into the available slots
|
360 |
-
new_dict = {}
|
361 |
-
for instructor in order:
|
362 |
-
new_dict[instructor] = availability[instructor]
|
363 |
-
availability = new_dict
|
364 |
|
365 |
partial_names = []
|
366 |
|
367 |
timeslots = initialize_timeslots(df)
|
|
|
|
|
368 |
schedules = []
|
369 |
schedule_obj = Schedule(timeslots)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
370 |
|
371 |
# Get the bare minimum of workshops that will be taught
|
372 |
distinct_slots = set()
|
373 |
-
for
|
374 |
-
for elem in
|
375 |
distinct_slots.add(elem)
|
376 |
num_distinct_slots = len(distinct_slots)
|
|
|
377 |
|
378 |
|
379 |
max_timeslots_list = [num_distinct_slots]
|
380 |
max_workshops_list = [num_distinct_slots]
|
|
|
381 |
|
382 |
-
find_all_schedules(people, availability, schedule_obj, capacity, schedules, max_timeslots_list, max_workshops_list)
|
383 |
|
384 |
-
|
385 |
|
386 |
|
387 |
res = classify_schedules(people, schedules, partial_names, total_timeslots, max_timeslots_list[0])
|
@@ -411,8 +437,6 @@ def main(df, capacity:int, num_results: int, og_slots: list):
|
|
411 |
else:
|
412 |
results = f"{beginning} are the best options."
|
413 |
|
414 |
-
#results += "(Remember that \"complete\" schedules are ones where everyone is teaching their desired number of workshops and every timeslot is filled.)"
|
415 |
-
|
416 |
|
417 |
directory = os.path.abspath(os.getcwd())
|
418 |
path = directory + "/schedule.csv"
|
|
|
63 |
|
64 |
|
65 |
# Extracts relevant information from the df with availability and puts it into a useable format
|
66 |
+
def convert_df(df, num_timeslots: int):
|
|
|
67 |
# Key: person's name
|
68 |
# Value: a list of their availability
|
69 |
availability = {}
|
70 |
+
|
71 |
+
|
72 |
+
# Key: person's name
|
73 |
+
# Value: how many workshops they want to teach
|
74 |
+
pref_dict = {}
|
75 |
+
|
76 |
+
# Instructors who can teach anytime
|
77 |
+
completely_available = []
|
78 |
+
|
79 |
for row in range(len(df)):
|
|
|
80 |
name = df.loc[row, NAME_COL]
|
81 |
+
curr_avail = df.loc[row, AVAIL_COL]
|
82 |
+
curr_avail = curr_avail.split(DELIMITER)
|
83 |
+
|
84 |
+
if len(curr_avail) == num_timeslots:
|
85 |
+
completely_available.append(name)
|
86 |
|
87 |
+
else:
|
88 |
+
curr_avail = [elem.strip() for elem in curr_avail]
|
89 |
+
availability[name] = curr_avail
|
90 |
+
pref_dict[name] = df.loc[row, NUM_WORKSHOPS_COL]
|
91 |
+
|
92 |
+
|
93 |
+
# Sorts a dictionary by length of the values such that the
|
94 |
+
# key associated with the shortest value is first in the list {orders}
|
95 |
+
order = sorted(availability, key=lambda k: len(availability[k]))
|
96 |
+
|
97 |
+
# The idea is start with people who are the LEAST available to teach,
|
98 |
+
# then put the more available instructors into the available slots
|
99 |
+
new_avail_dict = {}
|
100 |
+
|
101 |
+
for instructor in order:
|
102 |
+
new_avail_dict[instructor] = availability[instructor]
|
103 |
+
|
104 |
+
|
105 |
+
# Sorts the dict such that people who want to teach less are first in the dict
|
106 |
+
pref_dict = {k: v for k, v in sorted(pref_dict.items(), key=lambda item: item[1])}
|
107 |
+
|
108 |
+
people = []
|
109 |
+
for name,number in pref_dict.items():
|
110 |
if number == 1:
|
111 |
people.append(name)
|
112 |
|
|
|
115 |
for i in range(number):
|
116 |
people.append(name)
|
117 |
|
|
|
|
|
|
|
|
|
118 |
|
119 |
+
return {'people': people, 'availability': new_avail_dict, 'completely_available': completely_available}
|
120 |
|
121 |
|
122 |
|
|
|
170 |
# Unchoose (remove that person from the timeslot)
|
171 |
schedule_obj.remove(person, time)
|
172 |
# NOTE: this will not generate a full timeslot, but could still lead to a good schedule
|
|
|
173 |
else:
|
174 |
if len(people) == 1:
|
175 |
find_all_schedules([], availability, schedule_obj, capacity, schedules, max_timeslots_list, max_workshops_list)
|
176 |
else:
|
177 |
find_all_schedules(people[1:len(people)], availability, schedule_obj, capacity, schedules, max_timeslots_list, max_workshops_list)
|
178 |
+
|
179 |
|
180 |
return
|
181 |
|
|
|
270 |
|
271 |
|
272 |
# Classifies schedules into two categories: complete and incomplete:
|
273 |
+
# Complete = everyone is teaching desired number of timeslots and each timeslot has at least one workshop
|
274 |
# NOTE: I'm using "valid" instead of "complete" as a variable name so that I don't mix it up
|
275 |
# Incomplete = not complete
|
276 |
def classify_schedules(people: list, schedules: list, partial_names: list, total_timeslots: int, max_timeslots_filled: int) -> tuple:
|
|
|
373 |
# Big wrapper function that calls the other functions
|
374 |
def main(df, capacity:int, num_results: int, og_slots: list):
|
375 |
descrip_dict = get_description_dict(df)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
376 |
|
377 |
partial_names = []
|
378 |
|
379 |
timeslots = initialize_timeslots(df)
|
380 |
+
total_timeslots = len(timeslots)
|
381 |
+
print(total_timeslots)
|
382 |
schedules = []
|
383 |
schedule_obj = Schedule(timeslots)
|
384 |
+
|
385 |
+
# Convert the df with everyone's availability to a usable format
|
386 |
+
res = convert_df(df, total_timeslots)
|
387 |
+
people = res['people']
|
388 |
+
availability = res['availability']
|
389 |
+
completely_available = res['completely_available']
|
390 |
+
print(', '.join(people))
|
391 |
+
print(availability)
|
392 |
+
print(f"These instructors are completely avaialable: {', '.join(completely_available)}")
|
393 |
+
|
394 |
+
|
395 |
|
396 |
# Get the bare minimum of workshops that will be taught
|
397 |
distinct_slots = set()
|
398 |
+
for slots in availability.values():
|
399 |
+
for elem in slots:
|
400 |
distinct_slots.add(elem)
|
401 |
num_distinct_slots = len(distinct_slots)
|
402 |
+
print(num_distinct_slots)
|
403 |
|
404 |
|
405 |
max_timeslots_list = [num_distinct_slots]
|
406 |
max_workshops_list = [num_distinct_slots]
|
407 |
+
|
408 |
|
|
|
409 |
|
410 |
+
find_all_schedules(people, availability, schedule_obj, capacity, schedules, max_timeslots_list, max_workshops_list)
|
411 |
|
412 |
|
413 |
res = classify_schedules(people, schedules, partial_names, total_timeslots, max_timeslots_list[0])
|
|
|
437 |
else:
|
438 |
results = f"{beginning} are the best options."
|
439 |
|
|
|
|
|
440 |
|
441 |
directory = os.path.abspath(os.getcwd())
|
442 |
path = directory + "/schedule.csv"
|