Python-计算不同值的总和

时间:2019-08-19 11:09:09

标签: python combinations itertools

给出如下元组列表:

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

]

进一步说明输出的逻辑:

在两个输入中,第一个元组的行为均与笛卡尔乘积中的行为相同。 但是,除第一个以外的所有其他元组都将一起迭代(或压缩)。另外,如果说一个元组一起迭代“用完了值”,那么我们将使用元组中的最后一个值。

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

3 个答案:

答案 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)