Python: Как проверить, является ли вложенный список по существу пустым?

Есть ли способ Pythonic проверить, если список (вложенный список с элементами и списками) по существу пустой? То, что я подразумеваю под пустым здесь, состоит в том, что в списке могут быть элементы, но это также пустые списки.

Pythonic способ проверить пустой список работает только в плоском списке:

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

Например, все следующие списки должны быть положительными для пустоты:

alist = []
blist = [alist]               # [[]]
clist = [alist, alist, alist] # [[], [], []]
dlist = [blist]               # [[[]]]

Ответ 1

Я объединил использование isinstance() от Ants Aasma и all(map()) от Stephan202, чтобы сформировать следующее решение. all([]) возвращает True, и функция полагается на это поведение. Я думаю, что он имеет лучшее из того и другого, и лучше, поскольку он не полагается на исключение TypeError.

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

Ответ 2

Если вам не нужно перебирать списки, проще, так что что-то вроде этого будет работать:

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

Однако было бы хорошо отделить рекурсивную итерацию, которую вы, скорее всего, повторно используете в другом месте и проверяете, что она не возвращает никаких элементов. Таким образом, если механизм изменения итерации вам необходимо реализовать в одном месте. Например, когда вам нужно поддерживать произвольные вложенные итерации или вложенные 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

Ответ 3

Простой код, работает для любого итеративного объекта, а не только для списков:

>>> 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, если его аргумент является пустой.

Ответ 4

Я не думаю, что есть очевидный способ сделать это в 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)).

Ответ 5

Простой рекурсивный чек будет достаточно, и мы вернемся как можно раньше, предположим, что вход не является списком или содержит не-списки, он не пуст.

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"

Вы можете еще больше улучшить его, чтобы проверить рекурсивный список или нет объектов списка, или может быть пустым dicts и т.д.

Ответ 6

def isEmpty(a):
    return all([isEmpty(b) for b in a]) if isinstance(a, list) else False

Просто.

Ответ 7

Используйте любую() функцию. Это возвращает True, если существует элемент в списке, отличный от пустого списка.

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

>> Empty list!

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