在python中组合n个列表的所有元素[关闭]

Posted

技术标签:

【中文标题】在python中组合n个列表的所有元素[关闭]【英文标题】:Combine all elements of n lists in python [closed] 【发布时间】:2016-01-26 15:31:10 【问题描述】:

有很多关于在 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 解决方案,对吧?

【问题讨论】:

不同子列表中的字母是否总是唯一的? 规格不清楚。定义组合。 应该有 20 个组合,而您只显示了 8 个,因此该列表要么不完整,要么存在未指定的规则。是哪个? 我明白他们的意思;我认为:不是通常意义上的组合,而是将子列表中的每个位置替换为其他子列表中相应位置的项目。有了这个定义,结果就有意义了。 那是矛盾的。如果@L3viathan 是正确的,那么您将只有 8 个组合,但如果您只想要所有组合,那么您将有 20 个 【参考方案1】:

我想我破译了这个问题:

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']]

【讨论】:

感谢您提供此解决方案! "so_called_combs" :D 你怎么称呼它? @coroner 我不知道,你用它做什么?我不会称它为组合,因为这意味着别的东西(见itertools.combinations 这并没有给出它所缺少的所有“组合”['a','e','w'] 和另外 23 个 @SirParselot 我将其解释为只替换了一个元素。由于我不知道他们真正想要什么,我只能猜测。但好点。 在我们的两个答案之间,我认为我们涵盖了所有角度【参考方案2】:

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

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'),而不是在排列方面

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

def check(data) #Check if all sub lists are same length
    for i in data:
        if len(i) != len(data[0]):
            return False
    return True

if check(data_small):
    print list(combinations(chain(*data_small), 3))

[('a', 'b', 'c'), ('a', 'b', 'd'), ('a', 'b', 'e'), ('a', 'b', 'f'),
 ('a', 'c', 'd'), ('a', 'c', 'e'), ('a', 'c', 'f'), ('a', 'd', 'e'),
 ('a', 'd', 'f'), ('a', 'e', 'f'), ('b', 'c', 'd'), ('b', 'c', 'e'), 
 ('b', 'c', 'f'), ('b', 'd', 'e'), ('b', 'd', 'f'), ('b', 'e', 'f'),
 ('c', 'd', 'e'), ('c', 'd', 'f'), ('c', 'e', 'f'), ('d', 'e', 'f')]

【讨论】:

【参考方案3】:

很抱歉迟到了,但这里是使用 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 和最后两行当然只是对语法的不必要利用,将表达式放在一行中,我希望人们不要将此作为良好编码实践的示例。

编辑 我刚刚意识到也许我应该做一个简短的解释。因此,内部创建每个子列表的a - 1 副本(转换为元组以进行哈希性和唯一性测试)并将它们链接在一起以允许permutations 发挥其魔力,即创建a 子列表的子列表的所有排列长度。然后将它们转换为一个集合,该集合消除了必然会发生的所有重复项,然后一个映射在每个唯一排列中提取ith 子列表的ith 元素。最后,a 是第一个子列表的长度,因为假定所有子列表的长度相同。

【讨论】:

以上是关于在python中组合n个列表的所有元素[关闭]的主要内容,如果未能解决你的问题,请参考以下文章

Python 求一个列表中所有元素组合出的最大数

Python限定组合

我需要帮助在python中提出一个函数,该函数可以将3个参数作为列表并给我所有元素的组合[重复]

Python:枚举列表中所有元素的可能组合

关于算法分析的问题,以找出n个元素中m个元素的所有组合

Python:获取列表顺序元素的所有组合