简体   繁体   English

Python:以条件递归创建一个整数列表的列表

[英]Python: Recursively create a list of lists of ints with conditions

I want to create all possible distributions of n items. 我想创建n个项目的所有可能的分布。 This refers to the commonly known pigeonhole principle. 这是指众所周知的鸽洞原理。

The following values are the result of Microsoft Excel: 以下值是Microsoft Excel的结果:

get_distributions(list, number_of_items_to_distribute)
get_distributions([], 1) = [[1]]
get_distributions([], 2) = [[1, 1], [2]]
get_distributions([], 3) = [[1, 1, 1], [1, 2], [2, 1], [3]]
get_distributions([], 4) = [[1, 1, 1, 1], [1, 1, 2], [1, 2, 1], [1, 3], [2, 1, 1], [2, 2], [3, 1], [4]]

I already have some code, but there are some issues with deleting the temporary lists. 我已经有一些代码,但是删除临时列表存在一些问题。

all_distributions = []

def get_distributions(distribution, items):

    print('call with distribution = ' + str(distribution) + ', items = ' + str(items))
    print('---------------')

    # base case
    if items == 0:
        all_distributions.append(distribution)
        print('end: ' + str(distribution))
        distribution.clear()
        return []

    # recursion
    else:
        for i in range(1, items + 1):
            distribution.append(i)
            get_distributions(distribution, items - i)

With this I get good results printed out after "end: ", but some values like [1, 2] (calling with n = 3) are missing. 这样,我可以在“ end:”之后打印出良好的结果,但是缺少诸如[1,2](n = 3的调用)之类的值。 Additionally to this the values are not appended to my all_distributions. 除此之外,这些值未附加到我的all_distributions中。

I'm interested in the way I tried to solve this problem. 我对尝试解决此问题的方式感兴趣。 Is this a good approach or am I absolutely wrong? 这是一个好方法还是我绝对错误?

The main problem with your code is that the list all_distributions ends up containing many references to the same input list distribution . 您的代码的主要问题是列表all_distributions最终包含许多对同一输入列表distribution引用。 When you call all_distributions.append(distribution) , the list distribution is not copied into the list all_distributions , but merely a reference to the list is appended. 当您调用all_distributions.append(distribution) ,列表distribution不会复制到列表all_distributions ,而只会添加对列表的引用。 You can fix this by explicitly inserting a copy: all_distributions.append(list(distribution)) 您可以通过显式插入副本来解决此问题: all_distributions.append(list(distribution))

A minimal fix to your code is to insert copies, remove distribution.clear() in the base case, and adding distribution.pop() after the recursive call: 对代码的最小修复是插入副本,在基本情况下删除distribution.clear() ,并在递归调用之后添加distribution.pop()

all_distributions = []

def get_distributions(distribution, items):
    if items == 0:
        all_distributions.append(list(distribution))
    else:
        for i in range(1, items + 1):
            distribution.append(i)
            get_distributions(distribution, items - i)
            distribution.pop()

get_distributions([], 3)
print(all_distributions)

Outputs: [[1, 1, 1], [1, 2], [2, 1], [3]] 输出: [[1, 1, 1], [1, 2], [2, 1], [3]] 1,1,1 [[1, 1, 1], [1, 2], [2, 1], [3]]


A better way is to avoid using distribution.append , and instead using the plus operator on lists, like so: 更好的方法是避免使用distribution.append ,而是对列表使用加号运算符,如下所示:

def get_distributions(distribution, items):
    if items == 0:
        all_distributions.append(distribution)
    else:
        for i in range(1, items + 1):
            d = distribution + [i]
            get_distributions(d, items - i)

The plus operator on lists creates a new list by concatenating the two given lists. 列表上的加号运算符通过串联两个给定列表来创建新列表。 In this case, we are concatenating a single element i on the right side of distribution to get a new copy containing the elements in distribution followed by i . 在这种情况下,我们将在distribution右侧连接单个元素i ,以获得一个新副本,其中包含distribution中的元素,后跟i


Another improvement is to avoid the global variable all_distributions , and instead return the list of distributions: 另一个改进是避免使用全局变量all_distributions ,而是返回分发列表:

def get_distributions(distribution, items):
    if items == 0:
        return [distribution]
    else:
        all_distributions = []
        for i in range(1, items + 1):
            d = distribution + [i]
            all_distributions += get_distributions(d, items - i)
        return all_distributions

print(get_distributions([], 4))

Outputs: [[1, 1, 1, 1], [1, 1, 2], [1, 2, 1], [1, 3], [2, 1, 1], [2, 2], [3, 1], [4]] 输出: [[1, 1, 1, 1], [1, 1, 2], [1, 2, 1], [1, 3], [2, 1, 1], [2, 2], [3, 1], [4]] 1,1,1,1 [[1, 1, 1, 1], [1, 1, 2], [1, 2, 1], [1, 3], [2, 1, 1], [2, 2], [3, 1], [4]]

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM