不使用生成器的python递归列表组合

lon*_*ngj 2 python algorithm recursion

我正在学习python3.为了更多地考虑递归,我想实现一个函数comb(n,k),它返回一个由一组{1,2,...,n}中的kk元素的所有组合组成的列表.

我认为使用循环是不明智的,因为嵌套循环的数量取决于k.所以我认为它与递归.我尝试编写受这个问题启发的功能, 但我无法得到正确的答案.

def combinations(sub, data_set, index, still_needed):
    if still_needed == 0:
        return sub

    for i in range(index, len(data_set)):
        sub.append(data_set[i])
        still_needed = still_needed - 1
        return combinations(sub, data_set, index+1, still_needed)

def comb(n, k):
    data_set = list(range(1, n+1))
    print (combinations([], data_set, 0, k))
Run Code Online (Sandbox Code Playgroud)

如果我测试Comb(6,3),我只得到[1,2,3].我想获得所有组合.我的代码中有什么问题?还是重要的错过了?我只是想学习python的递归,这不是一个功课,谢谢.


期待的结果如下:

[[1, 5, 6],
[2, 5, 6],
[3, 5, 6],
[4, 5, 6],
[1, 4, 6],
[2, 4, 6],
[3, 4, 6],
[1, 3, 6],
[2, 3, 6],
[1, 2, 6],
[1, 4, 5],
[2, 4, 5],
[3, 4, 5],
[1, 3, 5],
[2, 3, 5],
[1, 2, 5],
[1, 3, 4],
[2, 3, 4],
[1, 2, 4],
[1, 2, 3]]
Run Code Online (Sandbox Code Playgroud)

虽然订单并不重要.如果有任何pythonic方式来解决这个问题,我将不胜感激,例如.嵌套[expression for item in iterable](因为我尝试过但失败了).

再次感谢.

Eri*_*nil 5

函数中的问题是你returnfor循环中有一个语句:它在第一次迭代期间停止执行函数.

这是您可以用于递归的基本结构:

def combinations(n, k, min_n=0, accumulator=None):
    if accumulator is None:
        accumulator = []
    if k == 0:
        return [accumulator]
    else:
        return [l for x in range(min_n, n)
                for l in combinations(n, k - 1, x + 1, accumulator + [x + 1])]

print(combinations(6, 3))
# [[1, 2, 3], [1, 2, 4], [1, 2, 5], [1, 2, 6], [1, 3, 4], [1, 3, 5], [1, 3, 6], [1, 4, 5], [1, 4, 6], [1, 5, 6], [2, 3, 4], [2, 3, 5], [2, 3, 6], [2, 4, 5], [2, 4, 6], [2, 5, 6], [3, 4, 5], [3, 4, 6], [3, 5, 6], [4, 5, 6]]
Run Code Online (Sandbox Code Playgroud)

要检查结果是否正确,您可以对其进行测试itertools:

import itertools
print(list(itertools.combinations(range(1,7),3)))
# [(1, 2, 3), (1, 2, 4), (1, 2, 5), (1, 2, 6), (1, 3, 4), (1, 3, 5), (1, 3, 6), (1, 4, 5), (1, 4, 6), (1, 5, 6), (2, 3, 4), (2, 3, 5), (2, 3, 6), (2, 4, 5), (2, 4, 6), (2, 5, 6), (3, 4, 5), (3, 4, 6), (3, 5, 6), (4, 5, 6)]
print(
        list(itertools.combinations(range(1, 7), 3))
          ==
        [tuple(comb) for comb in combinations(6, 3)]
     )
# True
Run Code Online (Sandbox Code Playgroud)

  • 对.稍微改变一下,在函数声明中有可变对象是不好的做法(同样的对象将在函数的多次调用中使用,甚至跨越不同模块中的导入并且会产生不良结果).是的,itertools是一个更好的选择性能明智,问题是与递归有关,这是一个常见的模式:)还要记住python的递归限制(10k). (2认同)