为什么获得列表 Python 的所有可能性不起作用?



所以我做了一个简单的程序,假设从给定的列表中计算所有可能的列表。例如[1,2,3]程序假定返回:[1,2,3],[2,3],[1,3],[1],[2],[3],[]但是是"NoneType"对象没有属性"append ">

def __bacteria(mass_list, count, option_list):
if len(mass_list) == count:
return option_list
return __bacteria(mass_list,count+1, option_list.append(mass_list[count])) or __bacteria(mass_list,count+1, option_list)

那么,为什么它不起作用呢?让我们添加一些类型注释并运行MyPy这样的类型检查器,这些可以帮助我个人找出很多错误:

def __bacteria(mass_list: list[int], count: int, option_list: list[int]) -> list[list[int]]:
if len(mass_list) == count:
return option_list  # error: list[int] given but list[list[int]] expected
return __bacteria(mass_list, count + 1,
option_list.append(mass_list[count]) # error: None given but list[int] expected
) or __bacteria(mass_list , count + 1, option_list)

好的,到目前为止显示了2个错误。第一个是什么?好吧,您返回当前选项,而不是当前选项的列表。

对于第二个,list.append在适当的位置修改列表,并返回None。这两者都不是你想要的。你想要的是,正如@Michael Butscher所建议的:option_list + [mass_list[count]]。所以现在我们有了:

def __bacteria(mass_list: list[int], count: int, option_list: list[int]) -> list[list[int]]:
if len(mass_list) == count:
return [option_list]
return (__bacteria(mass_list, count + 1, option_list + [mass_list[count]]) or
__bacteria(mass_list, count + 1, option_list))

在运行类型检查器或运行代码时,不应该出现任何错误。但我敢打赌它打印错了东西。这怎么可能发生?

基本情况(if len(mass_list) == count(应该可以。第一个递归调用似乎也很好,第二个递归调用也很好。剩下什么?只有or

现在,当给定列表作为参数时,or会做什么?在交互式解释器上试用。[] or []的结果是什么?[1] or [2]的结果如何?[] or [0]的结果如何?当给定两个列表时,or实现的逻辑规则是什么?

那么我们在这里需要什么呢?好吧,我们知道__bacteria返回一个列表列表(确切地说是list[list[int]](,我们需要返回一个包含第一次递归调用返回的列表项和第二次递归调用返回来的列表项的列表列表。+就是这么做的!所以现在我们有了:

def __bacteria(mass_list: list[int], count: int, option_list: list[int]) -> list[list[int]]:
if len(mass_list) == count:
return [option_list]
return (__bacteria(mass_list, count + 1, option_list + [mass_list[count]]) +
__bacteria(mass_list, count + 1, option_list))

我们可以做得更好。首先,我们通过创建许多较小的列表并将它们复制多次连接来构建列表。试着给出一个更大的mass_list,看看你的程序是如何变慢的。

使其更快并使用更少内存的一种方法是使用生成器作为辅助函数。我将重命名函数和参数以使事情更清楚:

from typing import Iterator
def powerset(items: list[int]) -> list[list[int]]:
return list(powerset_helper(items, 0, []))
def powerset_helper(items: list[int], index: int, to_include: list[int]) -> Iterator[list[int]]:
if index == len(items):
yield to_include
return
yield from powerset_helper(items, index + 1, to_include + [items[index]])
yield from powerset_helper(items, index + 1, to_include)

不过,我们可以做得更好,那就是简单地使用@Dalmas Otieno的答案!:(

我认为您正在尝试获取集合的幂集。如果是这样的话,你可以按如下方式进行:

from itertools import chain, combinations
def all_possible_lists(iterable):
l = list(iterable)
pset = chain.from_iterable(combinations(l, n) for n in range(len(l)+1))
return [list(i) for i in pset]
print(all_possible_lists([1, 2, 3]))

输出为

[[], [1], [2], [3], [1, 2], [1, 3], [2, 3], [1, 2, 3]]

我想你正在寻找这个功率集,没有任何lib?

试试这个:

def powerSet(nums):
''' nums is a list, [1, 2, 3]
generate all subset - by adding one at a time
'''
ans = [[]]
for n in nums:
ans += [a + [n] for a in ans]

return ans
print(powerSet([1, 2, 3]))      # NB - if empty list is undesired, you could filter it out.

输出:

[[], [1], [2], [1, 2], [3], [1, 3], [2, 3], [1, 2, 3]]

最新更新