Python: How to check if a nested list is essentially empty?

Question:

Is there a Pythonic way to check if a list (a nested list with elements & lists) is essentially empty? What I mean by empty here is that the list might have elements, but those are also empty lists.

The Pythonic way to check an empty list works only on a flat list:

alist = []
if not alist:
    print("Empty list!")

For example, all the following lists should be positive for emptiness:

alist = []
blist = [alist]               # [[]]
clist = [alist, alist, alist] # [[], [], []]
dlist = [blist]               # [[[]]]
Asked By: Ashwin Nanjappa

||

Answers:

I don’t think there is an obvious way to do it in Python. My best guess would be to use a recursive function like this one :

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

Note that all only comes with Python >= 2.5, and that it will not handle infinitely recursive lists (for example, a = []; a.append(a)).

Answered By: Pierre Bourdon

A simple recursive check would be enough, and return as early as possible, we assume it input is not a list or contains non-lists it is not empty

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"

You can further improve it to check for recursive list or no list objects, or may be empty dicts etc.

Answered By: Anurag Uniyal

Simple code, works for any iterable object, not just lists:

>>> 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

This code makes the assumption that anything that can be iterated over will contain other elements, and should not be considered a leaf in the “tree”. If an attempt to iterate over an object fails, then it is not a sequence, and hence certainly not an empty sequence (thus False is returned). Finally, this code makes use of the fact that all returns True if its argument is an empty sequence.

Answered By: Stephan202

If you do not need to iterate through the lists, simpler is better, so something like this will work:

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

However, it would be good to separate the recursive iteration that you will most probably reuse elsewhere and checking that it returns no elements. This way if the mechanism of iteration changes you need to implement the change in one place. For instance when you need to support arbitrary nested iterables, or nested dicts.

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
Answered By: Ants Aasma

I have combined the use of isinstance() by Ants Aasma and all(map()) by Stephan202, to form the following solution. all([]) returns True and the function relies on this behaviour. I think it has the best of both and is better since it does not rely on the TypeError exception.

def isListEmpty(inList):
    if isinstance(inList, list): # Is a list
        return all( map(isListEmpty, inList) )
    return False # Not a list
Answered By: Ashwin Nanjappa
def isEmpty(a):
    return all(map(isEmpty,a)) if isinstance(a, list) else False

Simply.

Answered By: Oreille

Use the any() function. This returns True if any list within the list is not empty.

alist = [[],[]]
if not any(alist):
    print("Empty list!")

>> Empty list!

see: https://www.programiz.com/python-programming/methods/built-in/any

Answered By: Nahuel Brandán

If you want to check if the nested list has no item in it, you can use a Depth First Search (DFS) traversing method like this

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.

This is similar to @AshwinNanjappa’s answer but it is easier to understand.

Answered By: GoingMyWay

It is possible to check if a list of lists is empty or not by using len function to check if the list’s length equal to zero or not, then use any to give True if there is any True (There is at least one empty sublist), as shown:

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!!
Answered By: Qaddomi Obaid
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.