在python中组合n个列表的所有元素

时间:2016-01-26 15:31:10

标签: python list itertools

关于在python中组合和合并列表有很多问题和答案,但我还没有找到一种方法来创建所有元素的完整组合。

如果我有以下列表列表:

data_small = [ ['a','b','c'], ['d','e','f'] ]
data_big = [ ['a','b','c'], ['d','e','f'], ['u','v','w'], ['x','y','z'] ]

如何获得包含所有组合的列表列表? 对于data_small,这应该是:

[ [a,b,c], [d,b,c], [a,b,f], [a,e,c],
  [d,e,c], [d,b,f], [a,e,f], [d,e,f], ... ]

这也适用于data_big的任意数量的长度

我很确定有一个花哨的itertools解决方案,对吗?

3 个答案:

答案 0 :(得分:2)

我想我破译了这个问题:

def so_called_combs(data):
    for sublist in data:
        for sbl in data:
            if sbl==sublist:
                yield sbl
                continue
            for i in range(len(sublist)):
                c = sublist[:]
                c[i] = sbl[i]
                yield c

如果我理解正确,则返回所需的列表:

对于数据中的每个列表,每个元素都被替换(但每次只有一个元素)与其他每个列表中的相应元素(相同位置)。

对于data_big,返回:

[['a', 'b', 'c'], ['d', 'b', 'c'], ['a', 'e', 'c'], ['a', 'b', 'f'],
 ['u', 'b', 'c'], ['a', 'v', 'c'], ['a', 'b', 'w'], ['x', 'b', 'c'],
 ['a', 'y', 'c'], ['a', 'b', 'z'], ['a', 'e', 'f'], ['d', 'b', 'f'],
 ['d', 'e', 'c'], ['d', 'e', 'f'], ['u', 'e', 'f'], ['d', 'v', 'f'], 
 ['d', 'e', 'w'], ['x', 'e', 'f'], ['d', 'y', 'f'], ['d', 'e', 'z'],
 ['a', 'v', 'w'], ['u', 'b', 'w'], ['u', 'v', 'c'], ['d', 'v', 'w'],
 ['u', 'e', 'w'], ['u', 'v', 'f'], ['u', 'v', 'w'], ['x', 'v', 'w'],
 ['u', 'y', 'w'], ['u', 'v', 'z'], ['a', 'y', 'z'], ['x', 'b', 'z'],
 ['x', 'y', 'c'], ['d', 'y', 'z'], ['x', 'e', 'z'], ['x', 'y', 'f'],
 ['u', 'y', 'z'], ['x', 'v', 'z'], ['x', 'y', 'w'], ['x', 'y', 'z']]

答案 1 :(得分:1)

这是使用itertools排列和链函数的另一种方法。您还需要检查索引是否排列并且长度是否相同,以及是否有多个元素被替换

array(1,2,3)

这并不关心是否有多个元素被替换

from itertools import *
data_small = [ ['a','b','c'], ['d','e','f'] ]
data_big = [ ['a','b','c'], ['d','e','f'], ['u','v','w'], ['x','y','z'] ]

def check(data, sub):
    check_for_mul_repl = []
    for i in data:
        if len(i) != len(data[0]):
            return False

        for j in i:
            if j in sub:
                if i.index(j) != sub.index(j):
                    return False
                else:
                    if i not in check_for_mul_repl:
                        check_for_mul_repl.append(i)
    if len(check_for_mul_repl) <= 2:
        return True
print [x for x in list(permutations(chain(*data_big), 3)) if check(data_big, x)]

['a', 'b', 'c'], ['a', 'b', 'f'], ['a', 'b', 'w'], ['a', 'b', 'z'],
['a', 'e', 'c'], ['a', 'e', 'f'], ['a', 'v', 'c'], ['a', 'v', 'w'],
['a', 'y', 'c'], ['a', 'y', 'z'], ['d', 'b', 'c'], ['d', 'b', 'f'],
['d', 'e', 'c'], ['d', 'e', 'f'], ['d', 'e', 'w'], ['d', 'e', 'z'],
['d', 'v', 'f'], ['d', 'v', 'w'], ['d', 'y', 'f'], ['d', 'y', 'z'],
['u', 'b', 'c'], ['u', 'b', 'w'], ['u', 'e', 'f'], ['u', 'e', 'w'],
['u', 'v', 'c'], ['u', 'v', 'f'], ['u', 'v', 'w'], ['u', 'v', 'z'],
['u', 'y', 'w'], ['u', 'y', 'z'], ['x', 'b', 'c'], ['x', 'b', 'z'],
['x', 'e', 'f'], ['x', 'e', 'z'], ['x', 'v', 'w'], ['x', 'v', 'z'],
['x', 'y', 'c'], ['x', 'y', 'f'], ['x', 'y', 'w'], ['x', 'y', 'z']

我使用排列而不是组合的原因是因为from itertools import permutations, chain data_small = [ ['a','b','c'], ['d','e','f'] ] data_big = [ ['a','b','c'], ['d','e','f'], ['u','v','w'], ['x','y','z'] ] def check(data, sub): for i in data: if len(i) != len(data[0]): return False for j in i: if j in sub: if i.index(j) != sub.index(j): return False return True #If you really want lists just change the first x to list(x) print [x for x in list(permutations(chain(*data_big), 3)) if check(data_big, x)] ['a', 'b', 'c'], ['a', 'b', 'f'], ['a', 'b', 'w'], 61 more... 在组合方面等于('d','b','c')而不是排列

如果你只是想要组合,那么这就容易多了。你可以做到

('c','b','d')

答案 2 :(得分:0)

对于迟到的聚会感到抱歉,但这里是花哨的&#34; one-liner&#34; (使用itertools和非常有用的新Python 3.5解包概括)(顺便说一句,这是一种明显更快,更易读的可迭代类型转换方式,比如明确调用list, )---并假设独特的元素:

>>> from itertools import permutations, repeat, chain
>>> next([*map(lambda m: [m[i][i] for i in range(a)],
               {*permutations((*chain(*map(
                   repeat, map(tuple, l), repeat(a - 1))),), a)})]
         for l in ([['a', 'b', 'c'], ['d', 'e', 'f'], ['g', 'h', 'i']],)
         for a in (len(l[0]),))
[['g', 'h', 'f'], ['g', 'b', 'i'], ['g', 'b', 'f'],
 ['d', 'b', 'f'], ['d', 'h', 'f'], ['d', 'h', 'i'],
 ['a', 'e', 'c'], ['g', 'e', 'i'], ['a', 'h', 'i'],
 ['a', 'e', 'f'], ['g', 'e', 'c'], ['a', 'b', 'i'],
 ['g', 'b', 'c'], ['g', 'h', 'c'], ['d', 'h', 'c'],
 ['d', 'b', 'c'], ['d', 'e', 'c'], ['a', 'b', 'f'],
 ['d', 'b', 'i'], ['a', 'h', 'c'], ['g', 'e', 'f'],
 ['a', 'e', 'i'], ['d', 'e', 'i'], ['a', 'h', 'f']]

在生成器上使用next和后两行当然只是不必要的语法开发,将表达式放到一行中,我希望人们不要将它作为良好编码实践的一个例子。 / p>

修改 我刚才意识到也许我应该做一个简短的解释。因此,内部部分创建每个子列表的a - 1个副本(转换为元组以进行可靠性和唯一性测试)并将它们链接在一起以允许permutations执行其魔法,即创建所有子列表的排列a子列表长度。然后将它们转换为一个集合,该集合除去必然会发生的所有重复项,然后地图在每个唯一排列中拉出i子列表的i元素。最后,a是第一个子列表的长度,因为假定所有子列表具有相同的长度。