为啥扁平列表中的空白项目

Posted

技术标签:

【中文标题】为啥扁平列表中的空白项目【英文标题】:Why blank items in flattened list为什么扁平列表中的空白项目 【发布时间】:2018-05-14 17:11:09 【问题描述】:

我正在尝试使用递归函数来展平可能包含子列表项的已发送列表:

def myflatten(slist, outlist=[]):
    for sl in slist:
        if type(sl) == list:    
            outlist.append(myflatten(sl, outlist))
        else: 
            outlist.append(sl)
    return outlist

print("myflatten list=", myflatten([1,[5,6,7],3,4,[7,8,9]]))

输出:

myflatten list= [1, 5, 6, 7, [...], 3, 4, 7, 8, 9, [...]]

为什么每个子列表都会收到[...],我怎样才能避免收到这个?感谢您的帮助。

【问题讨论】:

[...] 表示列表包含自身 我认为问题在于您正在更新defaultoutlist 的引用。例如,如果你调用myflatten([1]),然后调用myflatten([2]),你会得到[1, 2] 这不是问题的原因,但请注意那里的函数定义中的Default mutable gotcha。即使您的代码正常工作,如果您多次调用它,它也可能会产生令人惊讶的结果。 @turbulencetoo 很有趣!以前没见过,每天都学点新东西! @Kevin 实际上,我认为这是问题的原因。这是一个递归调用。 【参考方案1】:

另一个不使用list.extend 的选项。我会重新排列您的代码,并尽量避免使用默认参数:

def myflatten(slist):
    flat = []
    if isinstance(slist, list):
        for item in slist:
            flat += myflatten(item)
    else:
        flat.append(slist)
    return flat

【讨论】:

@rnso 确实如此。效率上不知道有没有区别,反正应该不会太大。【参考方案2】:

您创建了一个无限列表。列表中的[...] 条目指向列表本身。详情请见this answer。

这是因为当您进行递归调用时,您传入outlist 对象本身,然后将其返回并附加到自身。一个微妙的问题!但是很容易解决;您将希望使用= 进行递归调用,而不是append。或者extend,然后传入一个空列表。

def myflatten(slist):
    outlist = []
    for sl in slist:
        if type(sl) == list:    
            outlist.extend(myflatten(sl))
        else: 
            outlist.append(sl)
    return outlist

你甚至可以去掉一个参数,这很好。

【讨论】:

【参考方案3】:

现有的答案很好地解释了为什么会出现 [...] 自引用,但他们建议的代码修订对解决等待咬你的 default mutable argument gotcha 没有任何作用。

这是一个不需要 outlist 参数的解决方案:

def myflatten(slist):
    outlist = []
    for sl in slist:
        if isinstance(sl, list):    
            outlist.extend(myflatten(sl))
        else: 
            outlist.append(sl)
    return outlist

print("myflatten list=", myflatten([1,[5,6,7],3,4,[7,8,9]]))

【讨论】:

是的,它运行良好。 extend 是一个有用的功能。 保留空白accumulator 作为参数在 Scheme/Racket/Lisp 派生语言中很常见(如在 ***.com/questions/29425944/… 中)【参考方案4】:

问题是 myflatten 正在返回一个列表。因此,当您将 myflatten 的结果附加到 outlist 时,它会附加一个列表。尝试设置 outlist 等于 myflatten 的结果:

def myflatten(slist, outlist=[]):
    for sl in slist:
        if type(sl) == list:    
            outlist = myflatten(sl, outlist) #HERE IS THE CHANGE
        else: 
            outlist.append(sl)
    return outlist

print("myflatten list=", myflatten([1,[5,6,7],3,4,[7,8,9]]))

【讨论】:

但是我发现后续调用会不断添加到由先前调用该函数创建的 outlist 中。如何纠正? @rnso 你能给我举个例子哦,你的意思是什么? 在你的函数上尝试print(myflatten([1])); print(myflatten([2]))。您将得到 [1,2] 作为第二个命令的输出。 有趣,学到了新东西。凯文的答案效果更好,因为它不使用 outlist 作为参数。我可以更新这个,但由于他的回答有效,除非你愿意,否则我不会更新。 看这个:***.com/questions/1132941/…

以上是关于为啥扁平列表中的空白项目的主要内容,如果未能解决你的问题,请参考以下文章

扁平化和过滤 ansible 中的复杂结构 - dict 列表中的 dict

Python 3:扁平化嵌套字典和字典中的列表

扁平化(不规则)Python 中关于 Pandas Dataframes 的列表列表

连接扁平数据

过滤列表项后,ListView 中的 SwiftUI TextField 变为空白

为啥树状结构,扁平化的网站利于seo优化