我试图创建一个程序,该程序从一个类生成学生组,但不创建之前创建的组。具体来说,我需要每周从同一组学生中创建2个新的学生实验室小组,并且我不会多次将同一个两个学生配对在一起。在前几周配对的学生将以某种方式作为输入。
过去的群体也需要排除他们的镜像,即如果[1,2]是过去的群体,[2,1]也是过去的群体。
我的节目如下。它解决了这个问题,但我认为它非常低效。如果它是一个更好的解决方案,我会接受完全不同的代码。
import numpy,random
from itertools import combinations
class_list="""a\nb\nc\nd\ne\nf\ng\nh\ni\nj\nk\nl\nm\nn\no\np
"""
students=class_list.splitlines()
#print len(students),students
combs=[map(int, comb) for comb in combinations(range(len(students)), 2)]
#print combs
done_list=[[0,4],[1,6],[2,13],[3,12],[8,10],[11,14],[15,9],
[0,13],[1,4],[2,7],[3,12],[5,6],[8,10],[14,15],
[0,1],[2,3],[4,5],[6,7],[8,9],[10,11],[12,15],[13,14],
[0,2],[1,3],[4,6],[5,7],[8,14],[10,9],[12,11],[15,13]]
for i_done in done_list:
if i_done in combs:
combs.remove(i_done)
f_done=False
while(1):
if f_done:
break
final_list=[]
final_list_used_students=[]
for _i in range(len(students)/2):
rand_i=random.randint(0,len(combs)-1)
if combs[rand_i][0] not in final_list_used_students and combs[rand_i][1] not in final_list_used_students:
final_list.append(combs[rand_i])
final_list_used_students.append(combs[rand_i][0])
final_list_used_students.append(combs[rand_i][1])
if len(final_list_used_students)==len(students):
f_done=True
break
print final_list
答案 0 :(得分:1)
首先,我们需要将现有的组转换为元组的集。每个都需要另外排序,因为这是itertools.combinations
生成它们的顺序。因此。
done_list=[[0,4],[1,6],[2,13],[3,12],[8,10],[11,14],[15,9], #first old set
[0,13],[1,4],[2,7],[3,12],[5,6],[8,10],[14,15],#2nd old set
[0,1],[2,3],[4,5],[6,7],[8,9],[10,11],[12,15],[13,14],#3rd old set
[0,2],[1,3],[4,6],[5,7],[8,14],[10,9],[12,11],[15,13]]#4th old set
done_set = {tuple(sorted(i)) for i in done_list}
然后我们可以创建一个生成函数,只生成不属于done_set
的元素:
from itertools import combinations
def unseen_combinations(items, n):
for i in combinations(items, n):
if i not in done_set:
done_set.add(i)
yield i
for combination in unseen_combinations(students, 2):
print(combination)
答案 1 :(得分:1)
所以基本上你想要每次都覆盖所有项目,每个项目只选择一次,顺序并不重要。所以我从以前采取了一种全新的不同方法:
import itertools
def find_path(optional_pairs, num_pairs, result, used_population):
if num_pairs == 0:
return result
while optional_pairs:
_pair = optional_pairs.pop(0)
if _pair[0] in used_population or _pair[1] in used_population:
continue
# Try omitting this _pair
pairs = list(optional_pairs)
result2 = find_path(pairs, num_pairs, list(result), list(used_population))
if result2:
return result2
# Try adding pair to path
used_pop = list(used_population)
used_pop.append(_pair[0])
used_pop.append(_pair[1])
result2 = list(result)
result2.append(_pair)
pairs = list(optional_pairs)
return find_path(pairs, num_pairs - 1, result2, used_pop)
return []
def get_duos(population, excluded_duos):
excluded_duos = excluded_duos + [(x[1], x[0]) for x in excluded_duos]
all_combinations = itertools.permutations(population, 2)
optional_pairs = set(all_combinations) - set(excluded_duos)
return find_path(list(optional_pairs), len(population) / 2, [], [])
print get_duos(['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'], [('a', 'c'), ('b', 'g'), ('f', 'd'), ('e', 'h'), ('b', 'f'), ('g', 'c'), ('a', 'e'), ('h', 'd')])
我使用了另一个答案中提到的itertools.permutations
,从列表中删除了排除(及其镜像)并对其进行了处理。现在唯一的技巧是确保我们不选择一对可以创建无解的方案 - 因为重叠对在覆盖所有项目时无法与其连接。因此,我使用递归和每一步我尝试使用该对获得解决方案,直到我们找到解决方案。
享受
答案 2 :(得分:0)
对于N选择2,我想我刚刚听到你的规范归结为:
itertools.combinations(students, r=2)
文档位于https://docs.python.org/3/library/itertools.html#itertools.permutations
在运行之前,随意随机排列整个列表。
只需维护一套描述之前实验室作业的集合,并测试该集合中的成员资格,以拒绝重复提案。
编辑:谢谢你,Antti Haapala,关于组合评论
如何搜索此新集(不包含折扣组)并创建集合...
我想我不太明白这个问题。假设history
是具有历史学生对的集合,其中一对总是按排序顺序出现。那么这只是询问发生器和过滤的问题,是吗?
shuffled_students = [students[i]
for i in numpy.random.permutation(len(students))]
for pair in itertools.combinations(shuffled_students, r=2):
pair = sorted(pair)
if pair in history:
continue
history.add(pair)
schedule_this(pair)
答案 3 :(得分:0)
如果您不需要随机返回该组,那么您可能只记得最后一组返回并保持"递增"下一组。下面的示例代码显示了如何为50名学生做到这一点:
student_count = 50
students_nos = range(0, student_count)
current_group = (0, 1)
group_exhausted = False
def get_next_group():
global current_group
global group_exhausted
if group_exhausted:
return None
ret = current_group
if (current_group[0] == students_nos[student_count - 2]) and (current_group[1] == students_nos[student_count - 1]):
group_exhausted = True
if current_group[1] == students_nos[student_count - 1]:
current_group = (current_group[0] + 1, current_group[0] + 2)
else:
current_group = (current_group[0], current_group[1] + 1)
return ret
# Exmpale run.....
while True:
cur = get_next_group()
if cur is None:
break
print cur