Python 从集合创建组而不重复以前的组
我试图创建一个程序,从一个类中生成学生组,但不创建以前创建过的组。具体来说,我需要每周从同一组学生中创建两个新的学生实验组,我尽量不让同两个学生多次配对。前几周配对的学生将以某种方式作为输入 过去的组也需要排除镜像,即如果[1,2]是过去的组,[2,1]也是过去的组 我的程序如下。它解决了问题,但我想它效率很低。如果是更好的解决方案,我会接受完全不同的代码Python 从集合创建组而不重复以前的组,python,combinations,Python,Combinations,我试图创建一个程序,从一个类中生成学生组,但不创建以前创建过的组。具体来说,我需要每周从同一组学生中创建两个新的学生实验组,我尽量不让同两个学生多次配对。前几周配对的学生将以某种方式作为输入 过去的组也需要排除镜像,即如果[1,2]是过去的组,[2,1]也是过去的组 我的程序如下。它解决了问题,但我想它效率很低。如果是更好的解决方案,我会接受完全不同的代码 import numpy,random from itertools import combinations class_list="""a
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
对于N choose 2,我想我刚刚听说您的规格可以归结为:
itertools.combinations(students, r=2)
文档位于
在运行整个列表之前,可以随意排列整个列表
只需维护一组描述先前实验任务的集合,并测试组合在该集合中的成员资格,以拒绝重复的建议
编辑:谢谢你,安蒂·哈帕拉,谢谢你的评论
如何搜索此新集合(不包含折扣组)并创建集合
我想我不太明白这个问题。假设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)
首先,我们需要将已经存在的组转换为一组元组。每个都需要额外排序,因为这是
itertools.compositions
生成它们的顺序。因此
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\u集成员的元素
:
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)
因此,基本上您希望每次都覆盖所有项目,其中每个项目只选择一次,并且顺序并不重要。因此,我采取了一种与以前完全不同的新方法:
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
,从列表中删除了被排除的(及其镜像),并进行了处理。现在唯一的诀窍是确保我们不会选择一对可以创建“无”解决方案的配对,因为还押配对在覆盖所有项目时无法与其连接。因此,我使用递归,每一步我都会尝试得到一个有对和无对的解,直到找到解为止
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
享受如果您不需要随机返回组,那么您可以只记住最后返回的组,并继续“递增”下一组。下面的示例代码显示了如何为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
什么团体?2-组合?为什么这是精心设计的代码,以及为什么您要使用Python 2-这有特殊要求吗?精心设计是因为这是我的要求,尝试给出我的示例,如果可以轻松修改以生成解决方案,那么我建议您立即切换-Python 3是新手的首选语言。无论如何,您真的需要随机-为什么不排序?可能相关:这会查找组,但不会对已使用的组进行折扣。@您可以创建一组已经看到的组,并丢弃那些已经是该组成员的组。是的,我可以使用set.remove(折扣组)进行此操作。但是我如何搜索这个新的集合(不包含折扣组)并创建一组[total students/2](此处为8)组学生。这就是我正在努力解决的问题。还有排列->组合这会产生尚未使用的组合。但是我如何搜索这个新的集合(不包含折扣组)并创建一组[total students/2](此处为8)组学生。这就是我正在努力解决的问题。我的解决方案只是循环所有可能的组合,并将它们随机添加到集合中,如果该组中的学生尚未添加到集合中。然后,当最终找到匹配项时,该选项退出;需要几秒钟的时间。这是一个很小的问题,它不会打折彼此为镜像的组,这会打折[1,2],但不会打折[2,1]。如果我尝试进行更改以添加所有镜像组,它会卡在while循环中。