使用设定规则随机化列表
Randomizing lists with set rules
我有一个项目,我想用一组规则制作一个列表随机发生器。
假设我有 1 个名为 guests 的列表,其中包含 9 个项目,1 个名为 hosts 的列表,包含 4 个项目,以及一个名为 meals 的列表,其中包含 3 个项目。
现在我想在主机之间随机分配这些客人,这样每个主机都有 3 位客人, 足够公平。现在它们都将连接到 meal 中的第一项。问题来了,当我想再次让他们在不同的主人之间争夺第二餐时,但是 none 已经在一起的客人在接下来的两餐中再次见面。
我最终还是想要它,这样我就可以拥有一个主机和来宾的动态列表,这些列表在输入后会自行解决。
我不想破解代码,只是在寻找到达那里的方法。
您需要跟踪两件事:
a) 哪些主人已经接待了哪些客人
b) 每顿饭,已经分配了哪些客人。
a项可以用字典来完成,字典使用每个主机的名称作为关键字。项目 b 只需要是一个列表,每次新餐都会重置。
一旦您开始跟踪该信息,然后在选择将分配给房东的客人之前,您可以使用您跟踪的这些信息来创建第二个中间列表,其中仅包括可以选择的客人,随机选择其中一位。
下面是我解决这个问题的方法:
import random
class Meal_Schedule:
''' A class for repeatedly dividing up multiple hosts amongst multiple guests
such that a guest will never be hosted by the same host twice
and will always be placed with different guests '''
def __init__(self, guests: list, hosts: list, meals: list):
''' guests and hosts should both be lists. Duplicate guest or host names are not supported,
and the duplicate names will be ignored. '''
self.guests = guests
self.hosts = hosts
self.meals = meals
self.previously_assigned = {host:[] for host in hosts}
def create_meal_schedule(self):
''' Do all of the scheduling
Example of the dictionary returned:
{
'Hamburger': {'host 1': ['Guest D', 'Guest A'],
'host 2': ['Guest B', 'Guest C']},
'Pizza': {'host 1': ['Guest B', 'Guest C'],
'host 2': ['Guest A', 'Guest D']}
}
'''
ret = {}
for meal in self.meals:
ret[meal] = self.plan_next_meal()
return ret
def plan_next_meal(self, guests_per_host=None):
''' Plans the next meal
guests_per_host should be a positive integer, or None to automatically calculate a sensible value
Returns a dictionary containing each host's guest list for the next meal '''
# self.previously_assigned keeps track of who has been assigned to a host in the past
# so we don't assign a guest to the same host twice
# and assigned_this_round will keep track of which guests have already been given a seat this round
# so we don't double book a guest to two different hosts
if guests_per_host is None:
if not self.hosts:
# So we don't get a vague division by zero error, we raise this error instead
raise RuntimeException('Must have at least one host')
guests_per_host = len(self.guests) // len(self.hosts)
if guests_per_host < 1:
guests_per_host = 1
assert guests_per_host > 1, 'guests_per_host must be an integer greater than 1'
ret = {}
assigned_this_round = []
for host in self.hosts:
guest_list = self._create_guest_list( host, guests_per_host,
exclude_these_guests = [*self.previously_assigned[host], *assigned_this_round] )
assigned_this_round.extend(guest_list)
ret[host] = guest_list
self.previously_assigned[host].extend(guest_list)
return ret
def _create_guest_list(self, host, guests_per_host, exclude_these_guests):
''' used when planning a meal to create a host's guest list '''
guests_pool = [ guest for guest in self.guests if guest not in exclude_these_guests ]
if len(guests_pool) <= guests_per_host:
return guests_pool
return random.sample(guests_pool, guests_per_host)
def display_schedule(self, schedule=None):
''' displays a schedule created with create_meal_schedule
on the console in a nice way '''
if schedule is None:
schedule = self.create_meal_schedule()
print()
for meal, plan in schedule.items():
print(f'-- {meal} Meal Plan --'.upper())
print()
for host, guest_list in plan.items():
print(f'Host: {host}')
print('Guess list:')
for guest in guest_list:
print(f' {guest}')
print()
print()
print()
guests = [f'Guest {x}' for x in 'ABCDEFGHI']
hosts = ['host1', 'host2', 'host3', 'host4']
meals = ['Hamburger', 'Pizza', 'Eggs']
scheduler = Meal_Schedule(guests, hosts, meals)
scheduler.display_schedule()
我有一个项目,我想用一组规则制作一个列表随机发生器。
假设我有 1 个名为 guests 的列表,其中包含 9 个项目,1 个名为 hosts 的列表,包含 4 个项目,以及一个名为 meals 的列表,其中包含 3 个项目。
现在我想在主机之间随机分配这些客人,这样每个主机都有 3 位客人, 足够公平。现在它们都将连接到 meal 中的第一项。问题来了,当我想再次让他们在不同的主人之间争夺第二餐时,但是 none 已经在一起的客人在接下来的两餐中再次见面。
我最终还是想要它,这样我就可以拥有一个主机和来宾的动态列表,这些列表在输入后会自行解决。
我不想破解代码,只是在寻找到达那里的方法。
您需要跟踪两件事: a) 哪些主人已经接待了哪些客人 b) 每顿饭,已经分配了哪些客人。
a项可以用字典来完成,字典使用每个主机的名称作为关键字。项目 b 只需要是一个列表,每次新餐都会重置。
一旦您开始跟踪该信息,然后在选择将分配给房东的客人之前,您可以使用您跟踪的这些信息来创建第二个中间列表,其中仅包括可以选择的客人,随机选择其中一位。
下面是我解决这个问题的方法:
import random
class Meal_Schedule:
''' A class for repeatedly dividing up multiple hosts amongst multiple guests
such that a guest will never be hosted by the same host twice
and will always be placed with different guests '''
def __init__(self, guests: list, hosts: list, meals: list):
''' guests and hosts should both be lists. Duplicate guest or host names are not supported,
and the duplicate names will be ignored. '''
self.guests = guests
self.hosts = hosts
self.meals = meals
self.previously_assigned = {host:[] for host in hosts}
def create_meal_schedule(self):
''' Do all of the scheduling
Example of the dictionary returned:
{
'Hamburger': {'host 1': ['Guest D', 'Guest A'],
'host 2': ['Guest B', 'Guest C']},
'Pizza': {'host 1': ['Guest B', 'Guest C'],
'host 2': ['Guest A', 'Guest D']}
}
'''
ret = {}
for meal in self.meals:
ret[meal] = self.plan_next_meal()
return ret
def plan_next_meal(self, guests_per_host=None):
''' Plans the next meal
guests_per_host should be a positive integer, or None to automatically calculate a sensible value
Returns a dictionary containing each host's guest list for the next meal '''
# self.previously_assigned keeps track of who has been assigned to a host in the past
# so we don't assign a guest to the same host twice
# and assigned_this_round will keep track of which guests have already been given a seat this round
# so we don't double book a guest to two different hosts
if guests_per_host is None:
if not self.hosts:
# So we don't get a vague division by zero error, we raise this error instead
raise RuntimeException('Must have at least one host')
guests_per_host = len(self.guests) // len(self.hosts)
if guests_per_host < 1:
guests_per_host = 1
assert guests_per_host > 1, 'guests_per_host must be an integer greater than 1'
ret = {}
assigned_this_round = []
for host in self.hosts:
guest_list = self._create_guest_list( host, guests_per_host,
exclude_these_guests = [*self.previously_assigned[host], *assigned_this_round] )
assigned_this_round.extend(guest_list)
ret[host] = guest_list
self.previously_assigned[host].extend(guest_list)
return ret
def _create_guest_list(self, host, guests_per_host, exclude_these_guests):
''' used when planning a meal to create a host's guest list '''
guests_pool = [ guest for guest in self.guests if guest not in exclude_these_guests ]
if len(guests_pool) <= guests_per_host:
return guests_pool
return random.sample(guests_pool, guests_per_host)
def display_schedule(self, schedule=None):
''' displays a schedule created with create_meal_schedule
on the console in a nice way '''
if schedule is None:
schedule = self.create_meal_schedule()
print()
for meal, plan in schedule.items():
print(f'-- {meal} Meal Plan --'.upper())
print()
for host, guest_list in plan.items():
print(f'Host: {host}')
print('Guess list:')
for guest in guest_list:
print(f' {guest}')
print()
print()
print()
guests = [f'Guest {x}' for x in 'ABCDEFGHI']
hosts = ['host1', 'host2', 'host3', 'host4']
meals = ['Hamburger', 'Pizza', 'Eggs']
scheduler = Meal_Schedule(guests, hosts, meals)
scheduler.display_schedule()