Python 如何以渐进的方式生成无值的组合

Python 如何以渐进的方式生成无值的组合,python,python-3.x,Python,Python 3.x,我希望以渐进的方式在多个列表之间生成组合(具有空值)。例如,a=[1,2,3],b=[4,5,6],所需的输出应为 [(1, None), (2, None), (3, None)] [(1, 4), (2, None), (3, None)] [(1, 5), (2, None), (3, None)] [(1, 6), (2, None), (3, None)] [(1, None), (2, 4), (3, None)] [(1, None), (2, 5), (3, None)] [(1

我希望以渐进的方式在多个列表之间生成组合(具有空值)。例如,a=[1,2,3],b=[4,5,6],所需的输出应为

[(1, None), (2, None), (3, None)]
[(1, 4), (2, None), (3, None)]
[(1, 5), (2, None), (3, None)]
[(1, 6), (2, None), (3, None)]
[(1, None), (2, 4), (3, None)]
[(1, None), (2, 5), (3, None)]
[(1, None), (2, 6), (3, None)]
[(1, None), (2, None), (3, 4)]
[(1, None), (2, None), (3, 5)]
[(1, None), (2, None), (3, 6)]
[(1, 4), (2, 5), (3, None)]
[(1, 4), (2, 6), (3, None)]
[(1, 5), (2, 6), (3, None)]
[(1, 4), (2, None), (3, 5)]
[(1, 4), (2, None), (3, 6)]
[(1, 5), (2, None), (3, 6)]
[(1, None), (2, 4), (3, 5)]
[(1, None), (2, 4), (3, 6)]
[(1, None), (2, 5), (3, 6)]
[(1, 4), (2, 5), (3, 6)]
The number of combinations is 20
编辑: 结果的数量应为范围(len(a)+1内i的C(len(b),i)*C(len(a),i)之和,这意味着从列表“b”中选择i个元素与列表“a”中的i个元素相匹配。在这种情况下,20=C(3,3)*C(3,3)+C(3,2)*C(3,2)+C(3,1)*C(3,1)+C(3,0)*C(3,0)

我尝试了以下代码:

import itertools as it

def create_combos(first, *rest):
    for index in range(len(first)+1):
        for i in it.product([first], *(it.combinations(j,index) for j in rest)):
            yield list(it.zip_longest(*i))

count=0
for combo in create_combos(a, b):
    print(combo)
    count+=1
print('The number of combinations is '+str(count))
import itertools as it

def create_combos(first,rest):
    clone_rest=rest[:]
    clone_rest.insert(0,None)
    for sublist in it.product(clone_rest, repeat=len(first)):
        filtered_sublist=list(filter(None,sublist))
        if len(filtered_sublist)<=1:
            yield(list(zip(first,sublist)))
        else:
            for i in range(len(filtered_sublist)-1):
                if filtered_sublist[i]>=filtered_sublist[i+1]:
                    break
            else:
                yield(list(zip(first,sublist)))

count=0
for combo in create_combos(a,b):
    print(combo)
    count+=1
print('The number of combinations is '+str(count))
但是,输出中只有8种组合:

[(1, None), (2, None), (3, None)]
[(1, 4), (2, None), (3, None)]
[(1, 5), (2, None), (3, None)]
[(1, 6), (2, None), (3, None)]
[(1, 4), (2, 5), (3, None)]
[(1, 4), (2, 6), (3, None)]
[(1, 5), (2, 6), (3, None)]
[(1, 4), (2, 5), (3, 6)]
The number of combinations is 8
我认为这是因为数值的位置受到限制。然而,我想不出一种方法来改变它们的位置,而不手动将None值插入列表“b”并过滤掉那些不必要的组合,即下面的代码:

import itertools as it

def create_combos(first, *rest):
    for index in range(len(first)+1):
        for i in it.product([first], *(it.combinations(j,index) for j in rest)):
            yield list(it.zip_longest(*i))

count=0
for combo in create_combos(a, b):
    print(combo)
    count+=1
print('The number of combinations is '+str(count))
import itertools as it

def create_combos(first,rest):
    clone_rest=rest[:]
    clone_rest.insert(0,None)
    for sublist in it.product(clone_rest, repeat=len(first)):
        filtered_sublist=list(filter(None,sublist))
        if len(filtered_sublist)<=1:
            yield(list(zip(first,sublist)))
        else:
            for i in range(len(filtered_sublist)-1):
                if filtered_sublist[i]>=filtered_sublist[i+1]:
                    break
            else:
                yield(list(zip(first,sublist)))

count=0
for combo in create_combos(a,b):
    print(combo)
    count+=1
print('The number of combinations is '+str(count))
按需要导入itertools
def创建_组合(第一,其余):
克隆_rest=rest[:]
克隆\u rest.insert(0,无)
对于it.product中的子列表(clone\u rest,repeat=len(first)):
过滤的\子列表=列表(过滤器(无,子列表))
如果len(过滤的_子列表)=过滤的_子列表[i+1]:
打破
其他:
收益率(列表(zip(第一个,子列表)))
计数=0
对于create_组合中的组合(a,b):
打印(组合)
计数+=1
打印('组合数为'+str(计数))

尽管这段代码设法给了我想要的输出,但它显然不够有效,尤其是当每个列表中有更多的列表和更多的值时。有什么建议吗?

首先让我们来看看你所期待的:

你想要的不是C(6,3)=20

实际上你想要的是

[1,2,3]中i的C(3,i)*C(3,i)=20

为什么会这样

第一个选项是元组中的not None数,第二个选项是要在这些元组中选择的值

我在想办法解决这个问题。但我只是想解释一下数学,让大家都有同感

import itertools as it
from copy import deepcopy
a = [1,2,3]
b = [4,5,6]
def create_combos(a, l):
    n = len(a)
    incr = 0
    output = []
    default = [[x,None] for x in a]
    for i in range(n+1):
        choices_index = it.combinations(range(n),i)
        choices_value = list(it.combinations(l,i))
        for choice in choices_index:
            for values in choices_value:
                x = deepcopy(default)
                for index,value in zip(choice,values):
                    x[index][1] = value
                output += [x]
    print(len(output))
    print(output)



create_combos(a,b)

好的,现在我有了与您相同的输出,让我们试着找出一种优化这件事的方法。

如果顺序不重要,应该可以使用
itertools。组合

一个(长的)内衬是:

from itertools import combinations
combo_gen = ([(1, a), (2, b), (3, c)]
             for a, b, c in combinations([None,4,None,5,None,6], 3))

这里拾取的每一个第二个元素都是
None
,因此允许所有类型的
None
-散布。

您能补充一下问题陈述是什么吗?就像输出告诉我们的一样。想要解决这个问题:)谢谢你的关注。所需的输出应该能够生成所有可能的组合集,其中包含所有可能的元组。如您所见,元组的第一个元素固定为从“first”列表(在示例中为列表“a”)中提取。第二个元素来自“rest”列表(在本例中,列表“b”),并以渐进/升序的方式放置在非值之外,这表明“b”中没有与“a”匹配的值。为什么效率不够?你对效率有什么期望?为什么?这是一个紧密循环的一部分,还是问题所在?@JohanL这里提到的问题只是我试图解决的问题的一个非常简短的版本。最终,每个列表中将有成百上千个元素,而不是三个。在这种情况下,循环“it.product(clone_rest,repeat=len(first))”需要很长时间,最终会产生太多冗余子列表。因此,我正在寻找一种解决方案,它不需要过滤过程,只生成我需要的子列表。你也有同样的问题,如果你运行它,你会发现没有一个被认为是不同的,因此,你的output@BornTbeWasted:不,据我所知,这是通缉犯的行为。我们想要有20行,就像我生成的一样。我只是运行了你的代码,它看起来不像OP期望的那样。@JohanL首先,谢谢你的回答。实际上,前面的评论是正确的。你可以仔细检查我想要的输出。里面没有重复的行。所有20行都是不同的。我同意你的计算,但实际上,
itertools.combines()
保持值的顺序,这就是为什么我的
None
-散布版本可以工作的原因。下面是你的代码输出:[(1,None),(2,4),(3,None)],[(1,None),(2,4),(3,5)],[(1,None),(2,4),(3,None),…你可以看到有重复项…啊,是的,当然。你是对的。我错过了。谢谢你!@Borntbebowed非常感谢你提醒我数学错误!你是对的。我会编辑我的问题。@Borntbebowed谢谢!我会尝试将此应用于更大的数据集并测试效率。在优化方面,我会尝试使用g生成器(如“yield”),让函数一次输出一个组合。