简体   繁体   English

包括选择元素的组合(Python)

[英]Combinations Including Select Elements (Python)

In order to make the set of all combinations of numbers 0 to x, with length y, we do: 为了使数字0到x的所有组合的集合的长度为y,我们这样做:

list_of_combinations=list(combinations(range(0,x+1),y))
list_of_combinations=map(list,list_of_combinations)
print list_of_combinations

This will output the result as a list of lists. 这将结果输出为列表列表。

For example, x=4, y=3: 例如,x = 4,y = 3:

[[0, 1, 2], [0, 1, 3], [0, 1, 4], [0, 2, 3], [0, 2, 4], [0, 3, 4], [1, 2, 3], [1, 2, 4], 
[1, 3, 4], [2, 3, 4]]

I am trying to do the above, but only outputting lists that have 2 members chosen beforehand. 我正在尝试执行上述操作,但是仅输出预先选择2个成员的列表。

For instance, I would like to only output the set of the combos that has 1 and 4 inside it. 例如,我只想输出其中包含1和4的组合的集合。 The output would then be (for x=4, y=3): 输出将是(对于x = 4,y = 3):

[[0, 1, 4], [1, 2, 4], [1, 3, 4]]

The best approach I have now is to make a list that is y-2 length with all numbers of the set without the chosen numbers, and then append the chosen numbers, but this seems very inefficient. 我现在最好的方法是创建一个y-2长度的列表,其中包含集合中的所有数字而没有选择的数字,然后附加选择的数字,但这似乎效率很低。 Any help appreciated. 任何帮助表示赞赏。

*Edit: I am doing this for large x and y, so I can't just write out all the combos and then search for the selected elements, I need to find a better method. *编辑:我正在针对较大的x和y执行此操作,因此我不能只写出所有连击,然后搜索选定的元素,我需要找到一种更好的方法。

combinations() returns an iterable , so loop over that while producing the list: groups combinations()返回一个iterable ,因此在生成列表时对其进行循环:

[list(combo) for combo in combinations(range(x + 1), y) if 1 in combo]

This produces one list, the list of all combinations that match the criteria. 这将产生一个列表,即符合条件的所有组合的列表。

Demo: 演示:

>>> from itertools import combinations
>>> x, y = 4, 3
>>> [list(combo) for combo in combinations(range(x + 1), y) if 1 in combo]
[[0, 1, 2], [0, 1, 3], [0, 1, 4], [1, 2, 3], [1, 2, 4], [1, 3, 4]]

The alternative would be to produce y - 1 combinations of range(x + 1) with 1 removed, then adding 1 back in (using bisect.insort() to avoid having to sort afterwards): 另一种方法是产生y - 1range(x + 1)组合,并删除1 ,然后再添加1 (使用bisect.insort()以避免随后进行排序):

import bisect

def combinations_with_guaranteed(x, y, *guaranteed):
    values = set(range(x + 1))
    values.difference_update(guaranteed)
    for combo in combinations(sorted(values), y - len(guaranteed)):
        combo = list(combo)
        for value in guaranteed:
            bisect.insort(combo, value)
        yield combo

then loop over that generator: 然后循环生成器:

>>> list(combinations_with_guaranteed(4, 3, 1))
[[0, 1, 2], [0, 1, 3], [0, 1, 4], [1, 2, 3], [1, 2, 4], [1, 3, 4]]
>>> list(combinations_with_guaranteed(4, 3, 1, 2))
[[0, 1, 2], [1, 2, 3], [1, 2, 4]]

This won't produce as many combinations for filtering to discard again. 这样就不会产生太多组合来进行过滤以再次丢弃。

It may well be that for larger values of y and guaranteed numbers, just using yield sorted(combo + values) is going to beat repeated bisect.insort() calls. 对于较大的y值和有保证的数字,很可能仅使用yield sorted(combo + values)就能击败重复的bisect.insort()调用。

This should do the trick: 这应该可以解决问题:

filtered_list = filter(lambda x: 1 in x and 4 in x, list_of_combinations)

To make your code nicer (use more generators), I'd use this 为了使您的代码更好(使用更多的生成器),我将使用此代码

combs = combinations(xrange(0, x+1), y)
filtered_list = map(list, filter(lambda x: 1 in x and 4 in x, combs))

If you don't need the filtered_list to be a list and it can be an iterable, you could even do 如果您不需要filtered_list作为列表并且可以迭代,那么您甚至可以

from itertools import ifilter, imap, combinations
combs = combinations(xrange(0, x+1), y)
filtered_list = imap(list, ifilter(lambda x: 1 in x and 4 in x, combs))
filtered_list.next()
>  [0, 1, 4]
filtered_list.next()
>  [1, 2, 4]
filtered_list.next()
>  [1, 3, 4]
filtered_list.next()
>  Traceback (most recent call last):
>    File "<stdin>", line 1, in <module>
>  StopIteration

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

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