简体   繁体   English

列出所有组合但有限制

[英]List all combinations but with restriction

I've found the way to list all possible combinations of n elements grouped in sets of k elements. 我找到了列出以k个元素为一组的n个元素的所有可能组合的方法。 From maths, number is easy: n!/(k! * (nk)!) and python code is really simple using itertools: 从数学上看,数字很容易:n!/(k!*(nk)!),使用itertools的python代码非常简单:

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

But how to implement a restriction like: list only groups with only m elements in common ? 但是如何实现这样的限制:仅列出共有m个元素的组? so in previous example, for m=1, result should be: 因此,在前面的示例中,对于m = 1,结果应为:

[(1, 2, 3)]

With 5 elements and m=1: 有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)]

So my result is: 所以我的结果是:

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

Practical application of this question is how to group people, considering that only m people can repeat in result groups. 考虑到只有m个人可以在结果组中重复,此问题的实际应用是如何对人员进行分组。 Idea is to find groups with different people, to avoid groups of 'friends'. 想法是找到与不同的人在一起的团体,避免“朋友”的团体。 Imagine this for an school activity, repeated few days, where we want to ensure avoiding people to repeat with others as much as possible. 想象一下,这是重复几天的学校活动,我们要确保避免人们尽可能多地与他人重复。

One can use for loop to compare first combination with rest (using set intersection function "&" ): 可以使用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

Testing: 测试:

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

Output: 输出:

(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

You can use for loop: 您可以使用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)]

This way you will be able to control number of mutual members and get desired output. 这样,您将能够控制相互成员的数量并获得所需的输出。

It seems to be, that logical equivalent of result that you've got is something like this: 看来,您得到的结果在逻辑上是这样的:

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)

As in your example tuples don't share more than m common elements with any of other available. 就像在您的示例中一样,元组与其他任何可用元素之间共享的共有m个以上。 But as it's pointed in comments, that solution is strictly tide to order of operations. 但是正如评论中指出的那样,该解决方案严格遵循操作顺序。 First tuple determines what next tuples would be acceptable. 第一个元组确定可接受的下一个元组。

Mind the fact, that what you said in your comment is a problem which is little broader: grouping n people in groups of count k that don't have more than m people in common will give significantly more solutions than those that we have 'not filtered out'. 请注意,您在评论中说的是一个更广泛的问题:将n个人归为不超过m共同点的k群体将提供比我们没有的解决方案多得多的解决方案过滤掉”。 For example, you've pointed that for m = 1 and a = (1,2,3,4,5) solution is: 例如,您已经指出,对于m = 1a = (1,2,3,4,5)解决方案是:

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

...but actually there is many more solutions, for example: ...但是实际上还有更多解决方案,例如:

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

So I'm not completely sure if filtering combinations is proper way to solve your problem (nevertheless, it's not very clear what actually you'd like to achieve, so who knows). 因此,我不能完全确定过滤组合是否是解决问题的正确方法(不过,尚不清楚您实际上想实现什么目标,所以知道)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM