列出所有组合,但有限制

时间:2018-01-04 11:43:46

标签: python combinations itertools

我找到了列出以k个元素组分组的n个元素的所有可能组合的方法。从数学来看,数字很简单:n!/(k!*(n-k)!)和python代码使用itertools非常简单:

>>> import itertools
>>> a = [1,2,3,4]
>>> list(itertools.combinations(a,3))
[(1, 2, 3), (1, 2, 4), (1, 3, 4), (2, 3, 4)]

但是如何实现限制:仅列出只有m个元素的组?所以在前面的例子中,对于m = 1,结果应为:

[(1, 2, 3)]

有5个元素,m = 1:

>>> b=[1,2,3,4,5]
>>> list(itertools.combinations(b,3))
[(1, 2, 3), (1, 2, 4), (1, 2, 5), (1, 3, 4), (1, 3, 5), (1, 4, 5), (2, 3, 4), (2, 3, 5), (2, 4, 5), (3, 4, 5)]

所以我的结果是:

[(1, 2, 3), (1, 4, 5)]

这个问题的实际应用是如何对人进行分组,考虑到只有m个人可以在结果组中重复。想法是找到不同人群,避免群体的“朋友”。想象一下学校活动,重复几天,我们希望尽可能避免人们与他人重复。

3 个答案:

答案 0 :(得分:1)

可以使用for循环来比较第一个组合与休息(使用集合交集函数"&"):

def getsets(a, n):              # FUNCTION FOR THIS PURPOSE
    combos = list(itertools.combinations(a,n))  # GET ALL COMBINATIONS
    print(combos[0])            # PRINT FIRST COMBINATION
    for i in combos[1:]:        # FOR EACH OF REST
        if len(set(combos[0]) & set(i)) == 1:       # IF ONLY 1 ITEM COMMON WITH INITIAL
            print(i)            # PRINT IT

测试:

getsets([1,2,3,4], 3)
print("---------")
getsets([1,2,3,4,5], 3)

输出:

(1, 2, 3)   # INITIAL SET ONLY
---------
(1, 2, 3)   # INITIAL SET
(1, 4, 5)   # ONLY '1' IS COMMON WITH FIRST SET
(2, 4, 5)   # ONLY '2' IS COMMON WITH FIRST SET
(3, 4, 5)   # ONLY '3' IS COMMON WITH FIRST SET
{1, 2, 3}   # ONLY '4' IS COMMON WITH FIRST SET

答案 1 :(得分:0)

您可以使用for循环:

m = 1
combos = list(itertools.combinations(a,3))
result = []
for combo in combos:
    if result:
        if all([sum([1 for item in combo if item in tup]) == 1 for tup in result]):
            result.append(combo)
    else:
        result.append(combo)
result
#[(1, 2, 3), (1, 4, 5)]

通过这种方式,您将能够控制共有成员的数量并获得所需的输出。

答案 2 :(得分:0)

似乎是,您获得的结果的逻辑等价物是这样的:

class User(models.Model):
    first_name = models.CharField(max_length=20)
    last_name  = models.CharField(max_length=20)
    email_address = models.EmailField(max_length=50, unique=True)

    def __str__(self):
        return self.first_name

在您的示例中,元组不会与其他任何可用元素共享超过m个共同元素。但正如它在评论中指出的那样,该解决方案严格按照操作顺序进行。第一个元组确定下一个元组是可以接受的。

请注意,您在评论中所说的内容是一个更广泛的问题:将a = range(1,6) shared_elem_count = 1 group_count = 3 combinations = itertools.combinations(a, group_count) results = [] for combination in combinations: res_union = set().union(*results) intersection = set(combination).intersection(res_union) if len(intersection) <= shared_elem_count: results.append(combination) 人分组为n组,但不超过{{1}人们的共同点将提供比我们没有过滤掉的解决方案更多的解决方案&#39;。例如,您已指出km解决方案是:

m = 1

...但实际上还有更多解决方案,例如:

a = (1,2,3,4,5)

所以我不能完全确定过滤组合是否是解决问题的正确方法(尽管如此, 实际上你想要实现的目标 ,谁知道)。