这两个代码的Python子集递归函数有什么区别


def all_subsets(s):
    if len(s) == 1: return [[], s]
    else:
        sets = all_subsets(s[:-1])
        for e in sets:
            return sets + [e + [s[-1]]]

我尝试了上面的代码,它只返回 [[]、[1]、[2]、[3]]

所以我不小心尝试了如下所示的单班轮返回语句:

def all_subsets(s):
    if len(s) == 1: return [[], s]
    else:
        sets = all_subsets(s[:-1])
        return sets + [e + [s[-1]] for e in sets]

它奏效了。我不明白在 return 语句中使用 for 循环如何使这段代码工作;请帮助我了解它是如何工作的,因为我已经尝试在可视化工具上运行它,但我仍然不明白。

如果可能的话,如果您可以好心地让我的第一个代码在不使用一行返回语句的情况下工作。

提前一百万份感激之情

由于 for 循环中的 return 语句,第一种情况无法返回预期的结果。基本上代码将在 for 循环的第一次迭代中退出函数(仅对第一个子集求和,然后返回结果并结束函数调用)...第二个示例对所有子集求和,然后返回结果。

第一种情况下的问题是它在 for 循环中第一次返回。 对于第一个 e,它返回然后退出循环。 要修复代码,请执行以下操作:

def all_subsets(s):
    if len(s) == 1: return [[], s]
    else:
        sets = all_subsets(s[:-1])
        returnset = []
        for e in sets:
            returnset.extend([e,e + [s[-1]]])
        return returnset
s= [1,2,3]
print all_subsets(s)
[[], [3], [2], [2, 3], [1], [1, 3], [1, 2], [1, 2, 3]]

不过,我更喜欢列表理解版本。

除了有关代码的问题之外,还有一种方法可以获取所有子集的列表:

(来自: https://wiki.python.org/moin/Powerful%20Python%20One-Liners)

下面是一个工作函数,用于返回任何给定序列的所有子集的列表:

#!/python
f = lambda l: reduce(lambda z, x: z + [y + [x] for y in z], l, [[]])

。请注意,此 lambda 是递归定义的(就像在您的函数中一样)。

同样,对于 n 个元素,子集的大小增长为 2**n 也毫无价值。 换句话说,对于一组 10 个元素,子集有 1024 个元素。

如何思考和建模,考虑从 0 到 2**n 的所有二进制数......如果您枚举所有此类位字符串,并将每个位字符串视为要包含在相应子集中的项目的"掩码",那么您会发现您已经涵盖了从空集 (0) 到完整原始集 (11111...1111) 的所有可能子集。

这样做的一个含义是,您可以返回序列的"第 n 个"子集",而无需枚举所有中间的"子集"(吓唬引号,因为数学上一个集合是无序的;但这种处理取决于将位字符串映射到序列......在有序处理的"集"上)。

最新更新