两个列表之间的组合?


186

已经有一段时间了,我无法将自己的头围绕着我尝试制定的算法。基本上,我有两个列表,并且想要获得两个列表的所有组合。

我可能没有解释正确,所以这里有个例子。

name = 'a', 'b'
number = 1, 2

在这种情况下的输出将是:

1.  A1 B2
2.  B1 A2

棘手的部分是,“名称”变量中的项目可能比“数字”变量中的项目更多(数字将始终等于或小于名称变量)。

我很困惑如何进行所有组合(是否嵌套到循环?),甚至在名称中的项目比数字列表中的项目多的情况下,对于将名称变量中的项目进行移位的逻辑更加困惑。

我不是最好的程序员,但是如果有人可以帮助我阐明实现这一目标的逻辑/算法,我想可以试一试。所以我只是停留在嵌套的循环上。

更新:

这是带有3个变量和2个数字的输出:

name = 'a', 'b', 'c'
number = 1, 2

输出:

1.  A1 B2
2.  B1 A2
3.  A1 C2
4.  C1 A2
5.  B1 C2
6.  C1 B2


1
@ dm03514我看到了,并使用itertools找到了一些实现类似目标的示例,但是我使用python进行原型设计,但是会用另一种语言编写最终代码,所以我不想使用任何其他方式都无法使用的工具。
user1735075

1
您所要的并没有任何意义。如果第一个列表包含A,B,C,第二个列表包含1,2,您期望得到什么结果?如果您给出的示例具有4个不同的结果(一个字母和一个数字(A1,A2,B1,B2),或者两个列表的大小都必须相同),则可以这样做。
interjay 2012年

1
我同意interjay。请在不等大小的情况下指定结果,否则无法提供一般的解决方案。
巴库里(Bakuriu)2012年

大家好,我更新了答案,以显示3个名字和2个数字的输出。我以为我解释得很好,不确定为什么要投票。
user1735075

Answers:


93

注意:此答案是针对上面提出的特定问题的。如果您来自Google,只是在寻找一种使用Python获得笛卡尔积的方法,itertools.product或者您可能正在寻找简单的列表理解方法-请参见其他答案。


假设len(list1) >= len(list2)。然后,你似乎需要的是采取长的所有排列len(list2)list1,并与列表2项匹配。在python中:

import itertools
list1=['a','b','c']
list2=[1,2]

[list(zip(x,list2)) for x in itertools.permutations(list1,len(list2))]

退货

[[('a', 1), ('b', 2)], [('a', 1), ('c', 2)], [('b', 1), ('a', 2)], [('b', 1), ('c', 2)], [('c', 1), ('a', 2)], [('c', 1), ('b', 2)]]

1
结果恰好是我想要的,但是是否有可能分享如何做的逻辑呢?如果我将代码转换为C或Java,则将无法访问zip或itertools(尽管它们使生活变得非常轻松)
user1735075 2012年

3
@ user1735075看一下文档

1
@ user1735075:您知道python是开源的吗?因此,您可以简单地下载源代码并查看它们的作用。+1向Steak先生指出该文档实际上有一个不使用zip且类似的示例实现。
巴库里(Bakuriu)2012年

2
我实际上无法使它正常工作,即使使用您的示例……我得到的只是一个zip对象列表。
m1nkeh

1
@logic提供了应接受的解决方案。
Bernhard Wagner

499

最简单的方法是使用itertools.product

a = ["foo", "melon"]
b = [True, False]
c = list(itertools.product(a, b))
>> [("foo", True), ("foo", False), ("melon", True), ("melon", False)]

10
OP并不是要提供笛卡尔积,这个答案(以及其他大多数答案)并没有给出问题中指定的预期结果。
interjay

17
@interjay,您说的很对,但是由于太多的人似乎认为这个答案是正确的,所以我只能假设问题的标题没有上下文。
xpy

3
@xpy标题太短,无法解释所有内容。这就是为什么您需要阅读实际的问题。
interjay

10
OP希望进行置换,但是Google派人寻找组合(例如我)到这个答案-很高兴看到它获得了8倍的选票!
乔希·弗里德兰德

159

可能比上面最简单的方法更简单:

>>> a = ["foo", "bar"]
>>> b = [1, 2, 3]
>>> [(x,y) for x in a for y in b]  # for a list
[('foo', 1), ('foo', 2), ('foo', 3), ('bar', 1), ('bar', 2), ('bar', 3)]
>>> ((x,y) for x in a for y in b)  # for a generator if you worry about memory or time complexity.
<generator object <genexpr> at 0x1048de850>

没有任何进口


最好的解决方案!谢谢!其它解决方案要么是完全错误的或类似A> B等在特定情况下唯一的工作
菲利普·施瓦茨

3
大多数Pythonic解决方案!(并避免不必要的进口)
Dalker '18

6
时间复杂度为O(n ^ 2)
Deepak Sharma,

2
下注解决方案!裸露基础永远是最好的方法
Sabyasachi

22

我一直在寻找一个仅由唯一组合乘以自身的列表,该组合是作为此功能提供的。

import itertools
itertools.combinations(list, n_times)

这里作为Python文档 itertools的摘录,可能会帮助您找到所需的内容。

Combinatoric generators:

Iterator                                 | Results
-----------------------------------------+----------------------------------------
product(p, q, ... [repeat=1])            | cartesian product, equivalent to a 
                                         |   nested for-loop
-----------------------------------------+----------------------------------------
permutations(p[, r])                     | r-length tuples, all possible 
                                         |   orderings, no repeated elements
-----------------------------------------+----------------------------------------
combinations(p, r)                       | r-length tuples, in sorted order, no 
                                         |   repeated elements
-----------------------------------------+----------------------------------------
combinations_with_replacement(p, r)      | r-length tuples, in sorted order, 
                                         | with repeated elements
-----------------------------------------+----------------------------------------
product('ABCD', repeat=2)                | AA AB AC AD BA BB BC BD CA CB CC CD DA DB DC DD
permutations('ABCD', 2)                  | AB AC AD BA BC BD CA CB CD DA DB DC
combinations('ABCD', 2)                  | AB AC AD BC BD CD
combinations_with_replacement('ABCD', 2) | AA AB AC AD BB BC BD CC CD DD

11

您可能想尝试一个单行列表理解:

>>> [name+number for name in 'ab' for number in '12']
['a1', 'a2', 'b1', 'b2']
>>> [name+number for name in 'abc' for number in '12']
['a1', 'a2', 'b1', 'b2', 'c1', 'c2']

10

找出大量列表的所有组合的最佳方法是:

import itertools
from pprint import pprint

inputdata = [
    ['a', 'b', 'c'],
    ['d'],
    ['e', 'f'],
]
result = list(itertools.product(*inputdata))
pprint(result)

结果将是:

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

谢谢,很好的答案!
toinbis,

10

或KISS回答的简短清单:

[(i, j) for i in list1 for j in list2]

性能不如itertools,但您使用的是python,因此性能已经不是您的头等大事...

我也喜欢所有其他答案!


8

对interjay答案的微小改进,使结果成为一个扁平的列表。

>>> list3 = [zip(x,list2) for x in itertools.permutations(list1,len(list2))]
>>> import itertools
>>> chain = itertools.chain(*list3)
>>> list4 = list(chain)
[('a', 1), ('b', 2), ('a', 1), ('c', 2), ('b', 1), ('a', 2), ('b', 1), ('c', 2), ('c', 1), ('a', 2), ('c', 1), ('b', 2)]

来自此链接的参考


4

没有itertools

[(list1[i], list2[j]) for i in xrange(len(list1)) for j in xrange(len(list2))]

4

回答问题“给定两个列表,从每个列表中找到一个项目对的所有可能的排列”,并使用基本的Python功能(即,没有itertools),因此可以轻松地复制其他编程语言:

def rec(a, b, ll, size):
    ret = []
    for i,e in enumerate(a):
        for j,f in enumerate(b):
            l = [e+f]
            new_l = rec(a[i+1:], b[:j]+b[j+1:], ll, size)
            if not new_l:
                ret.append(l)
            for k in new_l:
                l_k = l + k
                ret.append(l_k)
                if len(l_k) == size:
                    ll.append(l_k)
    return ret

a = ['a','b','c']
b = ['1','2']
ll = []
rec(a,b,ll, min(len(a),len(b)))
print(ll)

退货

[['a1', 'b2'], ['a1', 'c2'], ['a2', 'b1'], ['a2', 'c1'], ['b1', 'c2'], ['b2', 'c1']]

2

更好的答案仅适用于所提供列表的特定长度。

这是一个适用于任何长度输入的版本。就组合和置换的数学概念而言,这也使算法更加清晰。

from itertools import combinations, permutations
list1 = ['1', '2']
list2 = ['A', 'B', 'C']

num_elements = min(len(list1), len(list2))
list1_combs = list(combinations(list1, num_elements))
list2_perms = list(permutations(list2, num_elements))
result = [
  tuple(zip(perm, comb))
  for comb in list1_combs
  for perm in list2_perms
]

for idx, ((l11, l12), (l21, l22)) in enumerate(result):
  print(f'{idx}: {l11}{l12} {l21}{l22}')

输出:

0: A1 B2
1: A1 C2
2: B1 A2
3: B1 C2
4: C1 A2
5: C1 B2
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.