Zip类函数,迭代列表中的多个项目并返回可能性



在以下代码中:

a = [["2022"], ["2023"]]
b = [["blue", "red"], ["green", "yellow"]]
c = [["1", "2", "3"], ["4", "5", "6", "7"], ["8", "9", "10", "11"], ["12", "13"]]

我想要一个输出这个的函数,但是对于任意数量的变量:

[
["2022", "blue", "1"],
["2022", "blue", "2"],
["2022", "blue", "3"],
["2022", "red", "4"],
["2022", "red", "5"],
["2022", "red", "6"],
["2022", "red", "7"],
["2023", "green", "8"],
["2023", "green", "9"],
["2023", "green", "10"],
["2023", "green", "11"],
["2023", "yellow", "12"],
["2023", "yellow", "13"],
]

我已经用itertools或zip搜索了一个函数来做这个,但还没有找到任何东西。

澄清一下,我的用例是迭代嵌套/多级下拉菜单的值(第一个下拉菜单返回选项,每个选项返回不同的下拉菜单,等等)。

首先,将第一个参数连接到一个只有一个元素的列表的列表中。

然后对于下一个参数中的每个sublist及其索引i,您选择前一次迭代的第i个列表res[i],并向aux添加len(子列表)列表,每个列表都是res[i],其中包含sublist中的一个项目。

from itertools import chain
def f(*args):
res = list(chain.from_iterable([[item] for item in l] for l in args[0]))
for arg in args[1:]:
aux = []
for i, sublist in enumerate(arg):
aux += [res[i] + [opt] for opt in sublist]
res = aux
return res

另外,如果你想验证传递给函数的参数是否正确,你可以使用:

def check(*args):
size = sum(len(l) for l in args[0])
for arg in args[1:]:
if len(arg) != size:
return False
size = sum(len(l) for l in arg)
return True
def foo(*args):
arrs = list(args)
prev = arrs[0]

def bar(arr1, arr2):
ans = []
for x, y in zip(arr1, arr2):
for el in y: 
ans.append(x + [el])
return ans

for curr in arrs[1:]:
ans = bar(prev, curr)
prev = ans

return ans
foo(a, b, c)
# [['2022', 'blue', '1'],
#  ['2022', 'blue', '2'],
#  ['2022', 'blue', '3'],
#  ['2022', 'red', '4'],
#  ['2022', 'red', '5'],
#  ['2022', 'red', '6'],
#  ['2022', 'red', '7'],
#  ['2023', 'green', '8'],
#  ['2023', 'green', '9'],
#  ['2023', 'green', '10'],
#  ['2023', 'green', '11'],
#  ['2023', 'yellow', '12'],
#  ['2023', 'yellow', '13']]

像d.b的答案,但使用reduce和列表推导:

from functools import reduce
from pprint import pprint
a = [["2022"], ["2023"]]
b = [["blue", "red"], ["green", "yellow"]]
c = [["1", "2", "3"], ["4", "5", "6", "7"], ["8", "9", "10", "11"], ["12", "13"]]
def foo(*args):
def bar(arr1, arr2):
return [
x + [el]
for x, y in zip(arr1, arr2)
for el in y
]
return reduce(bar, args)
pprint(foo(a, b, c))

输出(在线试试!):

[['2022', 'blue', '1'],
['2022', 'blue', '2'],
['2022', 'blue', '3'],
['2022', 'red', '4'],
['2022', 'red', '5'],
['2022', 'red', '6'],
['2022', 'red', '7'],
['2023', 'green', '8'],
['2023', 'green', '9'],
['2023', 'green', '10'],
['2023', 'green', '11'],
['2023', 'yellow', '12'],
['2023', 'yellow', '13']]

如果可能的话,我会使用不同的嵌套字典/列表输入集:

options = {
"2022": {
"blue": ["1", "2", "3"],
"red": ["4", "5", "6", "7"],
},
"2023": {
"green": ["8", "9", "10", "11"],
"yellow": ["12", "13"],
},
}

这使得树结构更清晰,也更安全,因为列表大小不可能不匹配。虽然重复的键将不再是可能的。

我们可以使用递归定义分支和listdict定义叶节点。

def iter_options(options, path=()):
if isinstance(options, dict):
for key, value in options.items():
yield from iter_options(value, path + (key,))
elif isinstance(options, list):
for key in options:
yield path + (key,)
else:
raise TypeError

用法:

>>> for row in iter_options(options):
...     print(row)
...
('2022', 'blue', '1')
('2022', 'blue', '2')
('2022', 'blue', '3')
('2022', 'red', '4')
('2022', 'red', '5')
('2022', 'red', '6')
('2022', 'red', '7')
('2023', 'green', '8')
('2023', 'green', '9')
('2023', 'green', '10')
('2023', 'green', '11')
('2023', 'yellow', '12')
('2023', 'yellow', '13')

最新更新