Python - 将不同值的组合计算为总和



给定一个元组列表,如下所示:

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)

最新更新