给出如下元组列表:
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'),
]
进一步说明输出的逻辑:
在两个输入中,第一个元组的行为均与笛卡尔乘积中的行为相同。 但是,除第一个以外的所有其他元组都将一起迭代(或压缩)。另外,如果说一个元组一起迭代“用完了值”,那么我们将使用元组中的最后一个值。
实现这一目标的有效方法是什么?
答案 0 :(得分:4)
通过提供额外的示例,我们可以弄清楚逻辑的外观。本质上,第一行经过特殊处理,以正常的“笛卡尔积”意义使用。
但是,其余的行有效地扩展到最大长度,并且被压缩在一起。对此进行编码,如下所示:
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')]
请注意,在将此功能用于用例之前,您可能需要根据需要添加更多输入验证。
答案 1 :(得分:0)
这适用于提供的数据。
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')
答案 2 :(得分:-4)
尝试
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)