给定一个元组列表,如下所示:
values = [
('a', 'b', 'c'),
('d', 'e'),
('f', 'g', 'h')
]
我想计算这些值的不同组合,但不是作为笛卡尔乘积,而是作为某些自定义规则的总和。澄清一下,如果我们计算这些元组之间的笛卡尔积,我们将得到 3*2*3 = 18 种不同的组合。但我的愿望是得到这样的东西:
combinations = [
('a', 'd', 'f'),
('a', 'e', 'g'),
('a', 'e', 'h'),
('b', 'd', 'f'),
('b', 'e', 'g'),
('b', 'e', 'h'),
('c', 'd', 'f'),
('c', 'e', 'g'),
('c', 'e', 'h')
]
因此,结果列表包含 9 种不同的组合,而不是 18 种。 包含 4 个元组的示例:
values = [
('a', 'b', 'c'),
('d', 'e'),
('f', 'g', 'h'),
('i', 'j', 'k', 'l')
]
结果将是
combinations = [
('a', 'd', 'f', 'i'),
('a', 'e', 'g', 'j'),
('a', 'e', 'h', 'k'),
('a', 'e', 'h', 'l'),
('b', 'd', 'f', 'i'),
('b', 'e', 'g', 'j'),
('b', 'e', 'h', 'k'),
('b', 'e', 'h', 'l'),
('c', 'd', 'f', 'i'),
('c', 'e', 'g', 'j'),
('c', 'e', 'h', 'k'),
('c', 'e', 'h', 'l'),
]
要进一步解释输出的逻辑,请执行以下操作:
在这两个输入中,第一个元组的行为与笛卡尔积中的行为相同。 但是,除第一个元组之外的所有其他元组都一起迭代(或压缩(。此外,如果一起迭代的元组之一可以说"值用完",我们将改用元组中的最后一个值。
实现这一目标的有效方法是什么?
通过提供的额外示例,我们可以弄清楚逻辑的外观。从本质上讲,第一行被特殊处理,并在正常的"笛卡尔乘积"意义上使用。
但是,其余行正在有效地扩展到最大长度,并被压缩在一起。编码起来,它可以看起来像这样:
from itertools import product
def extend_to_max_len(tup, length):
'''extends a tuple to a specified length by
filling the empty spaces with last element of given tuple
'''
fill_count = length - len(tup)
return (*tup, *[tup[-1]]*fill_count)
def non_cartesian_sum(values):
'''Expects a list of tuples.
gives the output according to the custom rules:
top: first row: to be used for cartesian product with zip of remaining rows
bottom: remaining rows: extended to longest length before zipping
'''
if len(values) < 2:
print("Check length of input provided")
return None
top = values[0]
bottom = values[1:]
max_len = max(len(row) for row in bottom)
bottom = [extend_to_max_len(row, max_len) for row in bottom]
out = [(first, *rest) for first, rest in product(top, zip(*bottom))]
return out
values = [
('a', 'b', 'c'),
('d', 'e'),
('f', 'g', 'h'),
('i', 'j', 'k', 'l')
]
out = non_cartesian_sum(values)
print(out)
输出:
[('a', 'd', 'f', 'i'),
('a', 'e', 'g', 'j'),
('a', 'e', 'h', 'k'),
('a', 'e', 'h', 'l'),
('b', 'd', 'f', 'i'),
('b', 'e', 'g', 'j'),
('b', 'e', 'h', 'k'),
('b', 'e', 'h', 'l'),
('c', 'd', 'f', 'i'),
('c', 'e', 'g', 'j'),
('c', 'e', 'h', 'k'),
('c', 'e', 'h', 'l')]
请注意,在将此函数用于您的用例之前,您可能需要根据需要添加更多输入验证。
这适用于提供的数据。
values = [
('a', 'b', 'c'),
('d', 'e'),
('f', 'g', 'h')
]
length_of_1 = len(values[1])
length_of_2 = len(values[2])
output = []
for item0 in values[0]:
for i in range(max(length_of_1, length_of_2)):
if i >= length_of_1:
item1 = values[1][-1]
else:
item1 = values[1][i]
if i >= length_of_2:
item2 = values[2][-1]
else:
item2 = values[2][i]
triple = (item0, item1, item2)
output.append(triple)
for tup in output:
print(tup)
输出:
('a', 'd', 'f') ('a', 'e', 'g') ('a', 'e', 'h') ('b', 'd', 'f') ('b', 'e', 'g') ('b', 'e', 'h') ('c', 'd', 'f') ('c', 'e', 'g') ('c', 'e', 'h')
试试这个
values = [
('a', 'b', 'c'),
('d', 'e'),
('f', 'g', 'h')
]
combination = [(a,b,c) for a in values[0] for b in values[1] for c in values[2]]
print(combination)