首页 > 解决方案 > 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'),

]

进一步解释输出的逻辑:

在这两个输入中,第一个元组的行为就像在笛卡尔积中一样。但是,除了第一个元组之外的所有其他元组都被迭代(或压缩)在一起。此外,如果一个被迭代在一起的元组可以这么说“用完值”,我们将使用元组中的最后一个值。

实现这一目标的有效方法是什么?

标签: pythoncombinationsitertools

解决方案


通过提供的额外示例,我们可以弄清楚逻辑的外观。本质上,第一行被特殊处理并用于正常的“笛卡尔积”。

然而,其余的行被有效地延伸到最大长度,并被拉在一起。对其进行编码,它可能如下所示:

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')]

请注意,在将此功能用于您的用例之前,您可能希望根据需要添加更多输入验证。


推荐阅读