在python中生成集合组合的最有效内存方法是什么?

时间:2012-04-12 00:45:56

标签: python performance memory combinatorics

这是我提出的代码:

def combinations(input):
    ret = ['']
    for i in range(len(input)):
        ret.extend([prefix+input[i] for prefix in ret])
    return ret

这个算法是O(2 ^ n)时间,但是可以减少空间吗?我听说使用yield可能有用,但无法考虑如何使用yield来实现。请不要使用内置组合功能 - 我想看看它是如何实现的。

3 个答案:

答案 0 :(得分:6)

你的问题明确表示你想看看代码会是什么样子,所以这里是O(n)空间解决方案的手工编码示例:

def combinations(input_list, acc=''):

    if not input_list:
        yield acc
        return

    next_val = input_list[0]

    for rest in combinations(input_list[1:], acc):
        yield rest

    acc += next_val

    # In python 3.2, you can use "yield from combinations(input_list[1:], acc)"
    for rest in combinations(input_list[1:], acc):
        yield rest

请注意,子字符串算法可能很昂贵(因为它必须多次复制字符串),因此就复杂性而言,这是一个稍微高效的版本:

def combinations(input_list, acc='', from_idx=0):

    if len(input_list) <= from_idx:
        yield acc
        return

    next_val = input_list[from_idx]

    for rest in combinations(input_list, acc, from_idx + 1):
        yield rest

    acc += next_val

    # In python 3.2, you can use "yield from combinations(input_list[1:], acc)"
    for rest in combinations(input_list, acc, from_idx + 1):
        yield rest

我没有使用Python 3.2,但如果你是这样的话,你可以这样写:

def combinations(input_list, acc='', from_idx=0):

    if len(input_list) <= from_idx:
        yield acc
        return

    next_val = input_list[from_idx]

    yield from combinations(input_list, acc, from_idx + 1)
    acc += next_val
    yield from combinations(input_list, acc, from_idx + 1)

我还应该注意,这是纯粹学术性的,因为itertools.combinations做得很好,适用于更广泛的输入(包括生成器表达式)。

答案 1 :(得分:3)

这样的事情应该这样做:

>>> print list(itertools.combinations({1, 2, 3, 4}, 3))
[(1, 2, 3), (1, 2, 4), (1, 3, 4), (2, 3, 4)]
>>>

答案 2 :(得分:2)

您可以在代码中使用yield,如下所示:

def combinations(input):
    ret = ['']
    yield ''
    for i in range(len(input)):
        for prefix in ret:
             combination = prefix+input[i]
             ret.extend(combination)
             yield combination

但它不会为你节省任何空间。

itertools.combinations documentation显示了一个(更多)更复杂的算法,它在恒定的空间中工作 - actual implementation在C中,但声称是等效的。