I have created a function in python to generate a roster for inspection by selecting a pair of inspectors each for two teams (Team A and B) each week for the whole year. The function accepts two lists, one list is optional. A pair cannot be formed exclusively from list2, the optional list. The count of each person in each Team should be almost the same.
The function works well except that there is little variety in the selection process. I want different pairs to be selected for the same team until all possible pairs are exhausted. I want each person to have a different partner each time he/she is selected for Team A. For example, if Kay, Pat are selected in Team A for Week 4, Kay should have a different partner the next time Kay is selected in Team A.
This is the code I have so far.
import pandas as pd
import random
def generate_roster(list1, list2=None):
if list2:
people = list1 + list2
else:
people = list1
# Ensure there are at least 4 people to form two pairs for Team A and Team B
if len(people) < 4:
raise ValueError("There should be at least four people to form two pairs for Team A and Team B.")
# Initialize dictionaries to keep track of when each person was last selected for Team A and Team B
last_selected_a = {person: -2 for person in people} # Start with -2 to allow immediate selection
last_selected_b = {person: -2 for person in people}
# Initialize dictionaries to count appearances in Team A and Team B
appearances_a = {person: 0 for person in people}
appearances_b = {person: 0 for person in people}
roster = []
for week in range(1, 53): # 52 weeks in a year
valid_selection = False
while not valid_selection:
# Sort people by their appearances in Team A and Team B to prioritize those with fewer appearances
sorted_people_a = sorted(people, key=lambda p: (appearances_a[p], last_selected_a[p]))
sorted_people_b = sorted(people, key=lambda p: (appearances_b[p], last_selected_b[p]))
selected_people = []
# Select two people for Team A ensuring no pair is formed exclusively from list2
for _ in range(2):
for person in sorted_people_a:
if person not in selected_people and (person in list1 or any(p in list1 for p in selected_people)):
selected_people.append(person)
break
# Select two people for Team B ensuring no pair is formed exclusively from list2
for _ in range(2):
for person in sorted_people_b:
if person not in selected_people and (person in list1 or any(p in list1 for p in selected_people[2:])):
selected_people.append(person)
break
team_a = selected_people[:2]
team_b = selected_people[2:]
# Check if this is the first week or if the same person is selected for the same team in successive weeks
if week == 1 or (not (set(team_a) & set(roster[-1]['Team A'].split(', ')) or set(team_b) & set(roster[-1]['Team B'].split(', ')))):
valid_selection = True
# Update the last selected week for each person
for person in team_a:
last_selected_a[person] = week
appearances_a[person] += 1
for person in team_b:
last_selected_b[person] = week
appearances_b[person] += 1
roster.append({
'Week Number': week,
'Team A': ', '.join(team_a),
'Team B': ', '.join(team_b)
})
df_roster = pd.DataFrame(roster)
return df_roster