Python 中具有边界条件的数组的所有可能组合?

问题描述

我有一个包含 4 个项目的列表,我想为给定的数组长度找到这 4 个项目的所有可能组合。例如:如果我指定我希望长度为 16,我想使用原始列表中的元素生成 16 个项目的所有可能组合。

我也有限制,所以我希望原始列表中的每个元素在生成的组合中出现一定的次数

例如:colors = np.array(["red","blue","green","neon green"])

我想生成以一定比例使用这些给定颜色的所有可能的 16 个元素数组:“红色”必须出现 4 次,“蓝色”必须出现 4 次,“绿色”+“霓虹绿”必须一起出现8 次(无论我们有 8 个果岭、0 个霓虹果岭,反之亦然,或者两者的混合,只要组合中的总和为 8。

我尝试使用 itertools.product 生成所有可能的组合,然后循环遍历每个组合以查看它是否符合我对“有效数组”的标准,但是对于 16 个元素的长组合,它超时(尽管此方法如果我想做 4 个或 8 个元素的长组合,确实有效)。

这是我当前的代码

def validCombinations(rows,columns):
    possibleCombinations = product(colors,repeat=rows) #generates all the possible combinations
    possibleCombos = [] #possible combinations that match our 1:2:1 ratio restriction
    

    counter = 1

    #loops through each combination and puts each ion in that combination into an array (array a)
    for c in product(possibleCombinations,repeat=columns):
        a = []
        for i in c:
            for j in i:
                a.append(j)


        #if a (the combination) contains a 1:2:1 ratio,then add it to the array of possible combos 
        if a.count("red") == (rows *columns)/4 and a.count("blue") == (rows *columns)/4 and (a.count("green") + a.count("neon green")) == (rows*columns)/2:
              possibleCombos.append(a)

  
    
    print(len(possibleCombos))
    return(possibleCombos)

validCombinations(2,2) #for a list of 4 elements
#validCombinations(4,4) #for a list of 16 elements
#validCombinations(2,4) etc..

itertools.product() 是正确的方法,还是有更快的替代方法

解决方法

我认为您尝试解决的问题不可行。可能有比您当前的方法更快的方法,但即使是理论上的最佳解决方案也需要很长时间,除非您有一台运行快速语言的极快计算机,而且由于您使用的是 Python,我认为情况并非如此。

您正在搜索四种颜色的所有可能组合。总共有 4**16 == 4294967296 种组合(每个项目有 4 个选择,应用产品计数规则),假设生成每个需要一毫秒,这将需要 1193 小时。显然,在 Python 中迭代所有这些是不可行的。

即使有更好的方法只生成符合您标准的组合,那仍然是 comb(16,4) * comb(12,4) * 2**8 == 230630400 组合(从 16 个位置中为红色选择 4 个位置,为蓝色选择 12 个位置中的 4 个位置,然后每个位置其余 8 个位置中的一个可以是两种颜色之一),再次假设每个位置都需要一毫秒来处理,即 64 小时。

您应该考虑将您的实现更改为不需要生成每个组合。也许您只需要检查某物是否是有效组合。或者也许你实际上并不需要这么大的数字;如果您只输入相对较小的数字,则您当前使用的代码不会比最佳代码慢多少。

,

就像 Alexander Wu 所说的那样,您可能需要重新考虑您的问题定义。 使用 itertools.product 很可能是接近的最佳方式,但您的 当前代码效率低下,导致其在相对较小的尺寸下运行时间过长。

但是,如果您拍摄具有有效组合,下面的代码将生成 效率更高:

import itertools

colors1 = ('blue','red')
colors2 = ('green','neon green')

def equalCount(c1,sz,curr):
    """ Even representation of c1 in curr. """
    return not all(curr.count(c) == sz for c in c1)

def validCombinations1(c1,c2,size):
    """ List valid combinations of colors."""
    sz = int(size / 2)
    col_iter1 = itertools.filterfalse(lambda x: equalCount(c1,sz/2,x),itertools.product(c1,repeat=sz))
    col_iter2 = itertools.product(c2,repeat=sz)
    vc = tuple(itertools.product(col_iter1,col_iter2))
    return tuple(v[0]+v[1] for v in vc)

vc1 = validCombinations1(colors1,colors2,4)
print(vc1)
print(len(vc1))
vc2 = validCombinations1(colors1,8)
print(len(vc2))
vc3 = validCombinations1(colors1,16)
print(len(vc3))

输出:

# (('blue','red','green','green'),#  ('blue','neon green'),'neon green',#  ('red','blue','neon green'))
# 8
# 48
# 17920

你的代码似乎产生了重复的排列;请注意,上面的代码也 产生一些排列,但没有重复。但不知道多一点 关于“规则”,很难构建更合适的程序。

我在笔记本电脑上运行了一些时间来比较结果。上面的代码, 即使有置换生成,也比较有利,有 10 微秒 与大小 4 的 235 微秒相比。

%timeit validCombinations(2,2)
235 µs ± 48.1 µs per loop (mean ± std. dev. of 7 runs,1000 loops each)
%timeit validCombinations1(colors1,4)
7.93 µs ± 608 ns per loop (mean ± std. dev. of 7 runs,100000 loops each)
%timeit validPermutations(validCombinations1(colors1,4))
10.5 µs ± 1.23 µs per loop (mean ± std. dev. of 7 runs,100000 loops each)

%timeit validCombinations1(colors1,8)
46.4 µs ± 5.58 µs per loop (mean ± std. dev. of 7 runs,10000 loops each)
%timeit validCombinations1(colors1,16)
5.87 ms ± 499 µs per loop (mean ± std. dev. of 7 runs,100 loops each)

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...