在Python中测试所有组合

the*_*ame 5 python combinations

我有两套选择:

optionList1 = [a1,a2,a3,...,an]
optionList2 = [b1,b2,b3,...,bn]
Run Code Online (Sandbox Code Playgroud)

选项列表中的元素数量不一定相等,我必须从第一个选项列表中选择两次.我如何确保我已经尝试了第一个列表中的两个选项和第二个列表中的一个的每个组合.下面的示例选择集......

selectedOptions = [an1,an2,bn]
Run Code Online (Sandbox Code Playgroud)

sha*_*ang 6

假设您不希望list1中有重复的条目,这里有一个生成器,您可以使用它来迭代所有组合:

def combinations(list1, list2):
    return ([opt1, opt2, opt3]
            for i,opt1 in enumerate(list1)
            for opt2 in list1[i+1:]
            for opt3 in list2)
Run Code Online (Sandbox Code Playgroud)

但是,这不会以不同的顺序从list1中选择相同的选项.如果你想同时获得[a1,a2,b1]和[a2,a1,b1],你可以使用:

def combinations(list1, list2):
    return ([opt1, opt2, opt3]
            for opt1 in list1
            for opt2 in list1
            for opt3 in list2 if opt1 != opt2)
Run Code Online (Sandbox Code Playgroud)

  • 在python术语中,生成器是使用`yield`的东西.这个缺点是将整个列表与选项存储在内存中. (2认同)

Pet*_*mit 6

您可以使用itertools.product.它返回所有可能的组合.

例如

for a1, a2, b in itertools.product(optionlist1,optionlist1,optionlist2):
    do_something(a1,a2,b)
Run Code Online (Sandbox Code Playgroud)

这将产生"双打"为[a1,a1,b2]和[a2,a3,b2],[a3,a2,b2].您可以使用过滤器修复此问题.以下内容可防止任何双打*:

for a1,a2,b in itertools.ifilter(lambda x: x[0]<x[1], itertools.product(optionlist1,optionlist1,optionlist2)):
    do_something(a1,a2,b)
Run Code Online (Sandbox Code Playgroud)

(*)这假设选项具有一些自然顺序,所有原始值都是如此.

回答也很好.我写了一些代码来比较它们:

from itertools import ifilter, product
import random
from timeit import repeat

def generator_way(list1, list2):
    def combinations(list1, list2):
        return ([opt1, opt2, opt3]
                for i,opt1 in enumerate(list1)
                for opt2 in list1[i+1:]
                for opt3 in list2)
    count = 0
    for a1,a2,b in combinations(list1,list2):
        count += 1

    return count

def itertools_way(list1,list2):
    count = 0
    for a1,a2,b in ifilter(lambda x: x[0] < x[1], product(list1,list1,list2)):
        count += 1
    return count

list1 = range(0,100)
random.shuffle(list1)
list2 = range(0,100)
random.shuffle(list2)

print sum(repeat(lambda: generator_way(list1,list2),repeat = 10, number=1))/10
print sum(repeat(lambda: itertools_way(list1,list2),repeat = 10, number=1))/10
Run Code Online (Sandbox Code Playgroud)

结果是:

0.189330005646
0.428138256073
Run Code Online (Sandbox Code Playgroud)

所以发电机方法更快.然而,速度并非一切.就个人而言,我发现我的代码"更清洁",但选择权在你手中!

(顺便说一句,他们给出了相同的计数,所以两者都同样正确.)


Mar*_*nen 6

结合productpermutationsitertools假设你不想第一个列表重复:

>>> from itertools import product,permutations
>>> o1 = 'a1 a2 a3'.split()
>>> o2 = 'b1 b2 b3'.split()
>>> for (a,b),c in product(permutations(o1,2),o2):
...     print a,b,c
... 
a1 a2 b1
a1 a2 b2
a1 a2 b3
a1 a3 b1
a1 a3 b2
a1 a3 b3
a2 a1 b1
a2 a1 b2
a2 a1 b3
a2 a3 b1
a2 a3 b2
a2 a3 b3
a3 a1 b1
a3 a1 b2
a3 a1 b3
a3 a2 b1
a3 a2 b2
a3 a2 b3
Run Code Online (Sandbox Code Playgroud)