【问题标题】:python combinations of multiple list多个列表的python组合
【发布时间】:2017-07-25 15:55:35
【问题描述】:

是否有任何 pythonic 方法来生成多个列表之间的组合? (类似于笛卡尔积但更复杂)

例子:

a = [1, 2, 3]
b = [4, 5, 6]
c = [7, 8, 9]
# ...
# there are more than 3 lists

预期输出:

1. [(1, 4, 7), (2, 5, 8), (3, 6, 9)]
2. [(1, 4, 8), (2, 5, 7), (3, 6, 9)]
3. [(1, 4, 9), (2, 5, 7), (3, 6, 8)]
4. [(1, 5, 7), (2, 4, 8), (3, 6, 9)]
5. ...

更新:

感谢您的快速回复~!!

澄清问题:

结果是列表a、b、c的笛卡尔积的所有非重复组合。

可以通过另一种丑陋的方法来完成:

1) 生成笛卡尔积的整个列表

from itertools import product, combinations, chain
t = list(product(a, b, c))

2) 使用组合产生所有可能的结果

p = list(combinations(t, 3))

3) 过滤重复条件

cnt = len(list(chain(a, b, c)))
f = [x for x in p if len(set(chain(*x))) == cnt]

更新2:

丑陋的方法产生的预期结果:

((1, 4, 7), (2, 5, 8), (3, 6, 9))
((1, 4, 7), (2, 5, 9), (3, 6, 8))
((1, 4, 7), (2, 6, 8), (3, 5, 9))
((1, 4, 7), (2, 6, 9), (3, 5, 8))
((1, 4, 8), (2, 5, 7), (3, 6, 9))
((1, 4, 8), (2, 5, 9), (3, 6, 7))
((1, 4, 8), (2, 6, 7), (3, 5, 9))
((1, 4, 8), (2, 6, 9), (3, 5, 7))
((1, 4, 9), (2, 5, 7), (3, 6, 8))
((1, 4, 9), (2, 5, 8), (3, 6, 7))
((1, 4, 9), (2, 6, 7), (3, 5, 8))
((1, 4, 9), (2, 6, 8), (3, 5, 7))
((1, 5, 7), (2, 4, 8), (3, 6, 9))
((1, 5, 7), (2, 4, 9), (3, 6, 8))
((1, 5, 7), (2, 6, 8), (3, 4, 9))
((1, 5, 7), (2, 6, 9), (3, 4, 8))
((1, 5, 8), (2, 4, 7), (3, 6, 9))
((1, 5, 8), (2, 4, 9), (3, 6, 7))
((1, 5, 8), (2, 6, 7), (3, 4, 9))
((1, 5, 8), (2, 6, 9), (3, 4, 7))
((1, 5, 9), (2, 4, 7), (3, 6, 8))
((1, 5, 9), (2, 4, 8), (3, 6, 7))
((1, 5, 9), (2, 6, 7), (3, 4, 8))
((1, 5, 9), (2, 6, 8), (3, 4, 7))
((1, 6, 7), (2, 4, 8), (3, 5, 9))
((1, 6, 7), (2, 4, 9), (3, 5, 8))
((1, 6, 7), (2, 5, 8), (3, 4, 9))
((1, 6, 7), (2, 5, 9), (3, 4, 8))
((1, 6, 8), (2, 4, 7), (3, 5, 9))
((1, 6, 8), (2, 4, 9), (3, 5, 7))
((1, 6, 8), (2, 5, 7), (3, 4, 9))
((1, 6, 8), (2, 5, 9), (3, 4, 7))
((1, 6, 9), (2, 4, 7), (3, 5, 8))
((1, 6, 9), (2, 4, 8), (3, 5, 7))
((1, 6, 9), (2, 5, 7), (3, 4, 8))
((1, 6, 9), (2, 5, 8), (3, 4, 7))

【问题讨论】:

  • 你想要一个迭代器吗?那么itertools.product(*args)就是你要找的东西。只需将您的列表设置为arg
  • @MarvinTaschenberger:你试过吗?
  • 为什么没有[(1, 4, 8), (2, 5, 9), (3, 6, 7)]
  • 您的问题并不完全清楚。您希望该输入数据有多少行输出?如果您想要 a、b 和 c 的每个排列的笛卡尔积,则需要 216 行。
  • 我已经为@PM2Ring 的建议编写了代码。如果是这种情况,请改写问题。

标签: python algorithm combinations itertools


【解决方案1】:

你想要的不是组合,而是排列。 3 个元素有 6 个排列,2 组排列的笛卡尔积有 36 个。PM 2Ring 最初怀疑你想要所有这 3 个排列,因为你的问题没有说明。如果您的问题中的代码产生了所需的输出,则意味着您希望 bc 置换而不是 a。最初,我编写了计算所有abc 的排列的代码。然而,由于a 不需要被置换,我们只需将其包装在一个列表中。这使我们非常接近所需的输出:

import itertools as it

a = [1, 2, 3]
b = [4, 5, 6]
c = [7, 8, 9]

for i in it.product([tuple(a)], it.permutations(b), it.permutations(c)):
    print(i)

输出以

开头的36行
((1, 2, 3), (4, 5, 6), (7, 8, 9))
((1, 2, 3), (4, 5, 6), (7, 9, 8))
((1, 2, 3), (4, 5, 6), (8, 7, 9))

它已经与您想要的几乎相同的格式,但索引已转置,因此o[x][y] 将匹配您所需输出的o[y][x]。我们使用一些zip magic 来转置它们。另外,此函数现在适用于任意数量的参数:

import itertools as it

a = [1, 2, 3]
b = [4, 5, 6]
c = [7, 8, 9]

def funnyperms(first, *rest):
    for i in it.product([first], *(it.permutations(j) for j in rest)):
        yield tuple(zip(*i))

for i in funnyperms(a, b, c):
    print(i)

输出是

((1, 4, 7), (2, 5, 8), (3, 6, 9))
((1, 4, 7), (2, 5, 9), (3, 6, 8))
((1, 4, 8), (2, 5, 7), (3, 6, 9))
((1, 4, 8), (2, 5, 9), (3, 6, 7))
((1, 4, 9), (2, 5, 7), (3, 6, 8))
((1, 4, 9), (2, 5, 8), (3, 6, 7))
((1, 4, 7), (2, 6, 8), (3, 5, 9))
((1, 4, 7), (2, 6, 9), (3, 5, 8))
((1, 4, 8), (2, 6, 7), (3, 5, 9))
((1, 4, 8), (2, 6, 9), (3, 5, 7))
((1, 4, 9), (2, 6, 7), (3, 5, 8))
((1, 4, 9), (2, 6, 8), (3, 5, 7))
((1, 5, 7), (2, 4, 8), (3, 6, 9))
((1, 5, 7), (2, 4, 9), (3, 6, 8))
((1, 5, 8), (2, 4, 7), (3, 6, 9))
((1, 5, 8), (2, 4, 9), (3, 6, 7))
((1, 5, 9), (2, 4, 7), (3, 6, 8))
((1, 5, 9), (2, 4, 8), (3, 6, 7))
((1, 5, 7), (2, 6, 8), (3, 4, 9))
((1, 5, 7), (2, 6, 9), (3, 4, 8))
((1, 5, 8), (2, 6, 7), (3, 4, 9))
((1, 5, 8), (2, 6, 9), (3, 4, 7))
((1, 5, 9), (2, 6, 7), (3, 4, 8))
((1, 5, 9), (2, 6, 8), (3, 4, 7))
((1, 6, 7), (2, 4, 8), (3, 5, 9))
((1, 6, 7), (2, 4, 9), (3, 5, 8))
((1, 6, 8), (2, 4, 7), (3, 5, 9))
((1, 6, 8), (2, 4, 9), (3, 5, 7))
((1, 6, 9), (2, 4, 7), (3, 5, 8))
((1, 6, 9), (2, 4, 8), (3, 5, 7))
((1, 6, 7), (2, 5, 8), (3, 4, 9))
((1, 6, 7), (2, 5, 9), (3, 4, 8))
((1, 6, 8), (2, 5, 7), (3, 4, 9))
((1, 6, 8), (2, 5, 9), (3, 4, 7))
((1, 6, 9), (2, 5, 7), (3, 4, 8))
((1, 6, 9), (2, 5, 8), (3, 4, 7))

将这些存储到一个集合中并与您的方法产生的值进行比较证明它们具有相同的输出:

print(set(funnyperms(a, b, c)) == set(f))

打印True,Q.E.D.

【讨论】:

  • 感谢您的回答!这是一个相当不错的方法,但结果不同(输入中的元素应该分成不同的)。我用预期的结果更新了问题。是否有任何算法可以产生该结果?
  • 什么意思?正如我所说,我的第二个代码生成一组与您提供的相同的元组......
  • 糟糕,很抱歉我错过了您的第二个代码。这个结果正是我想要的。棒极了!!非常感谢您的回答!
【解决方案2】:

您可以将 itertools 中的产品用于所有组合

>>> from itertools import product
>>> a = [1, 2, 3]
>>> b = [4, 5, 6]
>>> c = [7, 8, 9]
>>> A = [a,b,c]
>>> prod = list(product(*A))
>>> print(prod)

预期输出:

[(1, 4, 7), (1, 4, 8), (1, 4, 9), (1, 5, 7), (1, 5, 8), (1, 5, 9), (1, 6, 7), (1, 6, 8), (1, 6, 9), (2, 4, 7), (2, 4, 8), (2, 4, 9), (2, 5, 7), (2, 5, 8), (2, 5, 9), (2, 6, 7), (2, 6, 8), (2, 6, 9), (3, 4, 7), (3, 4, 8), (3, 4, 9), (3, 5, 7), (3, 5, 8), (3, 5, 9), (3, 6, 7), (3, 6, 8), (3, 6, 9)]

【讨论】:

  • 这看起来不像 OP 所期望的输出。
  • 如果你添加list(itertools.permutations(prod, 3))作为最终结果,我想你就有了。
猜你喜欢
  • 1970-01-01
  • 2019-08-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-12-19
  • 1970-01-01
  • 2020-06-20
相关资源
最近更新 更多