我正在编写一个函数,它将使用递归 return 嵌套列表中的一组唯一元素

I'm writing a function which will return a set of unique elements in a nested list using recursion

这是我目前所做的,

def unique(L):
    '''
    Returns set of unique elements in nested list L
    Ex.      unique([ 2, 1, 4, [ 3, [3, 4], 2 ], [2, 5, 6], 4, [ 2, 1 ]])
    returns: {1, 2, 3, 4, 5, 6}
    '''
    
    result = set()
    for item in L:
        if isinstance(item, list):
            unique(item)
        else:
            result.add(item)
    return result

但是当我 print(unique([ 2, 1, 4, [ 3, [3, 4], 2 ], [2, 5, 6], 4, [ 2, 1 ]]))

结果是{1, 2, 4}。 我试图弄清楚为什么递归没有在该嵌套列表中获取 5 和 6? 我只是想掌握递归概念,一开始很难。提前致谢!

您没有使用 unique(item) 的结果,每个 result 对于它的方法调用都是本地的。您需要当前和调用返回的内容的联合

def unique(L):
    result = set()
    for item in L:
        if isinstance(item, list):
            result = result.union(unique(item)) # with method
            # result |= unique(item)            # with operator
        else:
            result.add(item)
    return result

print(unique([2, 1, 4, [3, [3, 4], 2], [2, 5, 6], 4, [2, 1]]))  # {1, 2, 3, 4, 5, 6}

遇到子列表可以递归set.union

def unique(L):
    result = set()
    for item in L:
        if isinstance(item, list):
            result |= unique(item) # recurse, then union with current set
        else:
            result.add(item)
    return result

>>> unique([ 2, 1, 4, [ 3, [3, 4], 2 ], [2, 5, 6], 4, [ 2, 1 ]])
{1, 2, 3, 4, 5, 6}

在您当前的实现中,您调用 unique(item) 但随后不使用该递归调用的结果,因此返回的 result 被丢弃并且不会与当前项目集一起累积。

您只是忘记使用递归调用来更新 result

...
if isinstance(item, list):
    result.update(unique(item))
...

输出:

{1, 2, 3, 4, 5, 6}

一个相当优雅的方法是将展平与制作分开。

def flatten(nested_list):
    if isinstance(nested_list, list):
        for x in nested_list:
            for y in flatten(x):
                yield y
    else:
        yield nested_list

def unique(nested_list):
    return set(flatten(nested_list))

这不是展平嵌套列表的最有效方式。如果我们有一个 n 元素的列表,嵌套 n 层深,则需要 O(n^2) 时间来展平它。为了更快的扁平化,我们必须更聪明。

class FlattenIterator:
    def __init__(self, nested_list):
        self.stack = [iter((nested_list,))]
    
    def __iter__(self):
        return self
    
    def __next__(self):
        while self.stack:
            top_most = self.stack[-1]
            try:
                next_item = next(top_most)
                if isinstance(next_item, list):
                    self.stack.append(iter(next_item))
                else:
                    return next_item
            except StopIteration:
                self.stack.pop()
        raise StopIteration

def unique(nested_list):
    return set(FlattenIterator(nested_list))

假设参考图形成一棵树,此解决方案将与 space 的总量成线性关系。