Python:如何检查嵌套列表是否基本为空?

31
有没有Pythonic的方法可以检查一个列表(一个含有元素和列表的嵌套列表)是否为空?我所说的空是指列表可能有元素,但这些元素也是空列表。
检查空列表的Pythonic方式仅适用于扁平列表:
alist = []
if not alist:
    print("Empty list!")
例如,以下所有列表都应该是空的正例:
alist = []
blist = [alist]               # [[]]
clist = [alist, alist, alist] # [[], [], []]
dlist = [blist]               # [[[]]]
9个回答

37

3
我不认为在这种情况下使用any()是合适的。这在alist = [[], False]的情况下会失败。 - Monomaniac

20

我将 Ants Aasmaisinstance()Stephan202all(map()) 结合起来,得出了以下解决方案。 all([]) 返回 True,函数依赖于这种行为。我认为它兼具两者之长,更好,因为它不依赖于 TypeError 异常。

def isListEmpty(inList):
    if isinstance(inList, list): # Is a list
        return all( map(isListEmpty, inList) )
    return False # Not a list

4
如果输入是一个列表,则返回True,当且仅当该列表中每个元素都为空列表。如果输入不是列表,则返回False - Stephan202
Stephan202: 是的,这样就把它变成了一行代码!不过,我对这个 Python 条件表达式还不太熟悉。有点混乱,因为它的顺序和 C 三元运算符不一样哈哈 😉 - Ashwin Nanjappa
或者只需返回 isinstance(inList, list) and all(map(isListEmpty, inList))else False 几乎总是可以简化掉。 - user2357112

9

简单的代码,适用于任何可迭代对象,不仅限于列表:

>>> def empty(seq):
...     try:
...         return all(map(empty, seq))
...     except TypeError:
...         return False
...
>>> empty([])
True
>>> empty([4])
False
>>> empty([[]])
True
>>> empty([[], []])
True
>>> empty([[], [8]])
False
>>> empty([[], (False for _ in range(0))])
True
>>> empty([[], (False for _ in range(1))])
False
>>> empty([[], (True for _ in range(1))])
False

这段代码假设可迭代的任何内容都包含其他元素,因此不应被视为“树”中的叶子节点。如果尝试迭代对象失败,则它不是一个序列,因此肯定不是空序列(因此返回False)。最后,这段代码利用了all返回True的事实,如果其参数是一个空序列。


2
捕获所有异常是一件不好的事情,可能会导致隐藏代码中真正的错误。 - Denis Otkidach
3
+1 但我认为在Python中不应该使用map。对我来说,all( empty(x) for x in seq )听起来更好一些;-) (注:empty是指一个函数或方法,用于检测给定的对象是否为空) - Jochen Ritzel
当我使用这个代码时,出现了一个错误:RecursionError: maximum recursion depth exceeded while calling a Python object - BenjaminK

9
如果您不需要遍历列表,那么简单就是最好的选择,因此像这样的代码就可以工作:
def empty_tree(input_list):
    """Recursively iterate through values in nested lists."""
    for item in input_list:
        if not isinstance(item, list) or not empty_tree(item):
             return False
    return True

然而,最好将您可能在其他地方重复使用的递归迭代和检查它是否返回任何元素分开。这样,如果迭代机制发生更改,您只需要在一个地方实现更改。例如,当您需要支持任意嵌套的可迭代对象或嵌套字典时。

def flatten(input_list):
    """Recursively iterate through values in nested lists."""
    for item in input_list:
        if isinstance(item, list): # Use what ever nesting condition you need here
            for child_item in flatten(item):
                yield child_item
        else:
            yield item

def has_items(seq):
    """Checks if an iterator has any items."""
    return any(1 for _ in seq)

if not has_items(flatten(my_list)):
    pass

蚂蚁阿萨玛:我最喜欢你的解决方案的简洁性!我已经编辑了你的答案并将简单的解决方案提前了。谢谢! :-) - Ashwin Nanjappa
谢谢,你帮我省了很多时间。除了你的方法,其他所有尝试都没有成功。谢谢。 - Mo J. Mughrabi

6

我认为在Python中没有明显的方法来实现它。我最好的猜测是使用递归函数,像这样:

def empty(li):
    if li == []:
        return True
    else:
        return all((isinstance(sli, list) and empty(sli)) for sli in li)

请注意,all 只适用于 Python 版本大于等于 2.5,并且它无法处理无限递归的列表(例如:a = []; a.append(a))。

1
很好,我从未想过在Python中使用无限递归列表。看到它们甚至可以被打印出来真是太酷了;-) - Jochen Ritzel
+1 用于无限递归列表。现在前往此问题了解更多信息。 - Michael Dunn

2

一个简单的递归检查就足够了,并且尽早返回结果,我们假设输入不是列表或包含非列表项且不为空。

def isEmpty(alist):
    try:
        for a in alist:
            if not isEmpty(a):
                return False
    except:
        # we will reach here if alist is not a iterator/list
        return False

    return True

alist = []
blist = [alist]               # [[]]
clist = [alist, alist, alist] # [[], [], []]
dlist = [blist]               # [[[]]]
elist = [1, isEmpty, dlist]

if isEmpty(alist): 
    print "alist is empty"

if isEmpty(dlist): 
    print "dlist is empty"

if not isEmpty(elist): 
    print "elist is not empty"

你可以进一步改进它,以检查递归列表或无列表对象,或者可能为空的字典等。

2
isEmpty([1]) 失败了,这是一个相当大的问题(如果它只能用于已知为空的列表,那么检查空列表的函数就没有什么用处)。 - Pierre Bourdon
DelRoth:Anurag 现在好像已经修复了你评论的那个问题。 - Ashwin Nanjappa

2
def isEmpty(a):
    return all(map(isEmpty,a)) if isinstance(a, list) else False

简单明了。


0

可以使用len函数检查列表是否为空,然后使用any函数来判断是否存在空子列表,如果存在至少一个空子列表,则返回True,示例如下:

def empty(lis):
    # True if there is an empty sublist
    x = [True for i in lis if len(i) == 0]
    # any function will return True if at least there is one True in x
    if any(x):
        print("There is an empty sublist!!")
    else:
        print("There is no any empty sublist")
        
lis = [[1,2,3],[3],[2]]
empty(lis)
# The output is: There is no any empty sublist
lis2 = [[1,2,3],[],[]]
empty(lis2)
# The output is: There is an empty sublist!!

0
如果您想检查嵌套列表中是否没有任何项,可以使用深度优先搜索(DFS)遍历方法,如下所示。
def is_list_empty(values: list):
    
    if len(values) == 0:
        return True

    res = []
    for val in values:
        if isinstance(val, list):
            res.append(is_list_empty(val))
        else:
            res.append(False)
    
    return all(res)

v_list = [ [], [[1, 2], [], []], []]
is_list_empty(v_list)  # False, as there are two times in it.
v_list = [ [], [[], [], []], []]
is_list_empty(v_list)  # True, in fact ther is no item in it.

这与@AshwinNanjappa的答案类似,但更容易理解。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接