列表列表的所有组合[重复]
- 2024-12-11 08:47:00
- admin 原创
- 128
问题描述:
我基本上是在寻找一个 Python 版本的组合List<List<int>>
给定一个列表列表,我需要一个新列表,该列表提供列表之间所有可能的项目组合。
[[1,2,3],[4,5,6],[7,8,9,10]] -> [[1,4,7],[1,4,8],...,[3,6,10]]
列表数量未知,所以我需要一种适用于所有情况的方法。优雅可加分!
解决方案 1:
你需要itertools.product
:
>>> import itertools
>>> a = [[1,2,3],[4,5,6],[7,8,9,10]]
>>> list(itertools.product(*a))
[(1, 4, 7), (1, 4, 8), (1, 4, 9), (1, 4, 10), (1, 5, 7), (1, 5, 8), (1, 5, 9), (1, 5, 10), (1, 6, 7), (1, 6, 8), (1, 6, 9), (1, 6, 10), (2, 4, 7), (2, 4, 8), (2, 4, 9), (2, 4, 10), (2, 5, 7), (2, 5, 8), (2, 5, 9), (2, 5, 10), (2, 6, 7), (2, 6, 8), (2, 6, 9), (2, 6, 10), (3, 4, 7), (3, 4, 8), (3, 4, 9), (3, 4, 10), (3, 5, 7), (3, 5, 8), (3, 5, 9), (3, 5, 10), (3, 6, 7), (3, 6, 8), (3, 6, 9), (3, 6, 10)]
解决方案 2:
只需使用itertools.product
:
listOLists = [[1,2,3],[4,5,6],[7,8,9,10]]
for l in itertools.product(*listOLists):
print(l)
解决方案 3:
最优雅的解决方案是在 python 2.6 中使用itertools.product。
如果您没有使用 Python 2.6,文档itertools.product
实际上会显示一个等效函数来以“手动”方式完成产品:
def product(*args, **kwds):
# product('ABCD', 'xy') --> Ax Ay Bx By Cx Cy Dx Dy
# product(range(2), repeat=3) --> 000 001 010 011 100 101 110 111
pools = map(tuple, args) * kwds.get('repeat', 1)
result = [[]]
for pool in pools:
result = [x+[y] for x in result for y in pool]
for prod in result:
yield tuple(prod)
解决方案 4:
对于这个任务来说,直接使用递归没有任何问题,不需要外部依赖,如果你需要一个可以处理字符串的版本,那么这可能适合你的需要:
combinations = []
def combine(terms, accum):
last = (len(terms) == 1)
n = len(terms[0])
for i in range(n):
item = accum + terms[0][i]
if last:
combinations.append(item)
else:
combine(terms[1:], item)
>>> a = [['ab','cd','ef'],['12','34','56']]
>>> combine(a, '')
>>> print(combinations)
['ab12', 'ab34', 'ab56', 'cd12', 'cd34', 'cd56', 'ef12', 'ef34', 'ef56']
解决方案 5:
Numpy 可以做到这一点:
>>> import numpy
>>> a = [[1,2,3],[4,5,6],[7,8,9,10]]
>>> [list(x) for x in numpy.array(numpy.meshgrid(*a)).T.reshape(-1,len(a))]
[[ 1, 4, 7], [1, 5, 7], [1, 6, 7], ....]
解决方案 6:
可以使用基础 Python 来实现这一点。代码需要一个函数来展平列表的列表:
def flatten(B): # function needed for code below;
A = []
for i in B:
if type(i) == list: A.extend(i)
else: A.append(i)
return A
然后可以运行:
L = [[1,2,3],[4,5,6],[7,8,9,10]]
outlist =[]; templist =[[]]
for sublist in L:
outlist = templist; templist = [[]]
for sitem in sublist:
for oitem in outlist:
newitem = [oitem]
if newitem == [[]]: newitem = [sitem]
else: newitem = [newitem[0], sitem]
templist.append(flatten(newitem))
outlist = list(filter(lambda x: len(x)==len(L), templist)) # remove some partial lists that also creep in;
print(outlist)
输出:
[[1, 4, 7], [2, 4, 7], [3, 4, 7],
[1, 5, 7], [2, 5, 7], [3, 5, 7],
[1, 6, 7], [2, 6, 7], [3, 6, 7],
[1, 4, 8], [2, 4, 8], [3, 4, 8],
[1, 5, 8], [2, 5, 8], [3, 5, 8],
[1, 6, 8], [2, 6, 8], [3, 6, 8],
[1, 4, 9], [2, 4, 9], [3, 4, 9],
[1, 5, 9], [2, 5, 9], [3, 5, 9],
[1, 6, 9], [2, 6, 9], [3, 6, 9],
[1, 4, 10], [2, 4, 10], [3, 4, 10],
[1, 5, 10], [2, 5, 10], [3, 5, 10],
[1, 6, 10], [2, 6, 10], [3, 6, 10]]
解决方案 7:
这主要模仿了Jarret Hardie使用itertools.product给出的答案,但有以下区别:
这将参数传递给
itertools.product
内联,而不是通过变量a
- 因此*args
内联参数不需要语法如果你的mypy type-linter和我的一样,并且你可以让你的代码以其他方式“工作”带有
*args
内联product
参数的语法(如product(*[[1,2,3],[4,5,6],[7,8,9,10]])
),mypy
仍然可能会失败(类似于error: No overload variant of "product" matches argument type "List[object]"
)因此
mypy
,解决这个问题的方法是不要使用*args
这样的语法:
>>> import itertools
>>> list(itertools.product([1,2,3],[4,5,6],[7,8,9,10]))
[(1, 4, 7), (1, 4, 8), (1, 4, 9), (1, 4, 10), (1, 5, 7), (1, 5, 8), (1, 5, 9), (1, 5, 10), (1, 6, 7), (1, 6, 8), (1, 6, 9), (1, 6, 10), (2, 4, 7), (2, 4, 8), (2, 4, 9), (2, 4, 10), (2, 5, 7), (2, 5, 8), (2, 5, 9), (2, 5, 10), (2, 6, 7), (2, 6, 8), (2, 6, 9), (2, 6, 10), (3, 4, 7), (3, 4, 8), (3, 4, 9), (3, 4, 10), (3, 5, 7), (3, 5, 8), (3, 5, 9), (3, 5, 10), (3, 6, 7), (3, 6, 8), (3, 6, 9), (3, 6, 10)]
解决方案 8:
这个答案并不像使用 itertools 那样干净,但这些想法可能有用。
从这里zip() 的构造中汲取灵感,我们可以执行以下操作。
>>> a = iter([[1,2,3],[4,5,6],[7,8,9,10]])
>>> sentinel = object()
>>> result = [[]]
>>> while True:
>>> l = next(a,sentinel)
>>> if l == sentinel:
>>> break
>>> result = [ r + [digit] for r in result for digit in l]
>>> print(result)
[[1, 4, 7], [1, 4, 8], [1, 4, 9], [1, 4, 10], [1, 5, 7], [1, 5, 8], [1, 5, 9], [1, 5, 10], [1, 6, 7], [1, 6, 8], [1, 6, 9], [1, 6, 10], [2, 4, 7], [2, 4, 8], [2, 4, 9], [2, 4, 10], [2, 5, 7], [2, 5, 8], [2, 5, 9], [2, 5, 10], [2, 6, 7], [2, 6, 8], [2, 6, 9], [2, 6, 10], [3, 4, 7], [3, 4, 8], [3, 4, 9], [3, 4, 10], [3, 5, 7], [3, 5, 8], [3, 5, 9], [3, 5, 10], [3, 6, 7], [3, 6, 8], [3, 6, 9], [3, 6, 10]]
我们使用a
作为一个迭代器,以便连续获取它的下一个项,而无需事先知道有多少项。当我们用完 中的列表时,next
命令将输出sentinel
(这是一个专门为进行此比较而创建的对象,请参阅此处了解一些解释) ,从而触发语句,因此我们跳出循环。a
`if`
解决方案 9:
from itertools import product
list_vals = [['Brand Acronym:CBIQ', 'Brand Acronym :KMEFIC'],['Brand Country:DXB','Brand Country:BH']]
list(product(*list_vals))
输出:
[('品牌缩写:CBIQ', '品牌国家:DXB'),
('品牌缩写:CBIQ', '品牌国家:BH'),
('品牌缩写:KMEFIC', '品牌国家:DXB'),
('品牌缩写:KMEFIC', '品牌国家:BH')]