生成元组列表对的笛卡尔积

问题描述 投票:0回答:1

我需要帮助从元组列表生成组合,其中每个元组包含索引 0 处的字符串和索引 1 处的值列表。例如,考虑以下设置:

params = ['sn', 'tp', 'v1', 'temp', 'slew']

list_tuple = [('Serial Number', [12345]),
              ('Test Points', ['TestpointA', 'TestpointC']),
              ('Voltage_1', [3.0, 3.3, 3.6, 0.0]),
              ('Temperature Setpoint', [0, 60]),
              ('Slew_1', [200, 400, 800, 1600, 3200, 6400])]

我一直在使用嵌套循环来生成这些参数的所有可能组合,如图所示:

def generate_combinations(test_tuple, params):
    for sn in test_tuple[0][1]:
        for tp in test_tuple[1][1]:
            for v in test_tuple[2][1]:
                for temp in test_tuple[3][1]:
                    for slew in test_tuple[4][1]:
                        print(f'{params[0]}: ', sn)
                        print(f'{params[1]}: ', tp)
                        print(f'{params[2]}: ', v)
                        print(f'{params[3]}: ', temp)
                        print(f'{params[4]}: ', slew)
                        print('\n')

generate_combinations(list_tuple, params)

此方法有效,但不可扩展,因为嵌套循环的深度对应于

params
列表的长度,该长度可能会有所不同。元组中每个列表的长度也可以改变。我需要一个更动态的解决方案,最好没有显式嵌套循环。

我尝试使用递归,但没有达到预期的结果:

def not_working(list_tuple):
    for i in list_tuple:
        if isinstance(i, tuple):
            print(i[0])
            not_working(i[1])
        else:
            print(i)
            print('\n')

not_working(list_tuple)

如何在不使用显式嵌套循环的情况下动态实现所需的输出,无论

list_tuple
中的元组数量或每个子列表中的元素数量如何?

python for-loop recursion python-itertools nested-for-loop
1个回答
3
投票

您可以使用

itertools.product

import itertools
data = [('Serial Number', [12345]), ('Test Points', ['TestpointA', 'TestpointC']), ('Voltage_1', [3.0, 3.3, 3.6, 0.0]), ('Temperature Setpoint', [0, 60]), ('Slew_1', [200, 400, 800, 1600, 3200, 6400])]
params = ['sn', 'tp', 'v1', 'temp', 'slew']
for i in itertools.product(*[b for _, b in data]):
  print('\n'.join(f'{a}:{b}' for a, b in zip(params, i)))
  print('-'*20)

输出(前三个结果):

sn:12345
tp:TestpointA
v1:3.0
temp:0
slew:200
--------------------
sn:12345
tp:TestpointA
v1:3.0
temp:0
slew:400
--------------------
sn:12345
tp:TestpointA
v1:3.0
temp:0
slew:800
--------------------
...

虽然

itertools.product
(也许)是这个问题最干净的解决方案,但可以使用带有生成器的简单递归函数。

d
data
有什么区别?
在递归函数中,
d
在每次迭代时都会通过列表切片(
d[i+1:]
)进行变异。由于
d
的长度减小,而
len(d)
求的是函数作用域中声明的对象
d
的长度,所以它不会求出存储原始数据的列表的长度,而是求当前值传递给
combination
,每次调用都会减少。

def combination(d, current = []):
   if len(current) == len(data):
     yield current
   else:
     for i, a in enumerate(d):
       for c in a: 
         yield from combination(d[i+1:], current = current+[c])
       

for i in combination([b for _, b in data]):
  print('\n'.join(f'{a}:{b}' for a, b in zip(params, i)))
  print('-'*20)

输出(前三个结果):

sn:12345
tp:TestpointA
v1:3.0
temp:0
slew:200
--------------------
sn:12345
tp:TestpointA
v1:3.0
temp:0
slew:400
--------------------
sn:12345
tp:TestpointA
v1:3.0
temp:0
slew:800
--------------------
© www.soinside.com 2019 - 2024. All rights reserved.