2009-10-20 28 views
9

¿Hay alguna manera Pythonic a cheque si un lista (un anidada lista con los elementos & listas) es esencialmente vacío? Lo que quiero decir con vacío aquí es que la lista puede tener elementos, pero también son listas vacías.Python: ¿Cómo comprobar si una lista anidada está esencialmente vacía?

La forma Pythonic para comprobar una lista vacía sólo funcionan en una lista plana:

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

Por ejemplo, todas las siguientes listas debe ser positivo para el vacío:

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

Respuesta

8

he combinado el uso de isinstance() por Ants Aasma y all(map()) por Stephan202, para formar la siguiente solución. all([]) devuelve True y la función se basa en este comportamiento. Creo que tiene lo mejor de ambos y es mejor ya que no se basa en la excepción TypeError.

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

'return all (map (isListEmpty, inList)) if isinstance (inList, list) else False ':) – Stephan202

+0

Stephan202: ¡Sí, eso lo convierte en un auténtico juego de una sola línea! Sin embargo, no estoy tan cómodo con esta expresión condicional de Python. Un poco confuso ya que no está ordenado de la misma manera que el operador ternario ;-) –

4

no lo hago creo que hay una manera obvia de hacerlo en Python. Mi mejor conjetura sería el uso de una función recursiva como éste:

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

Tenga en cuenta que all sólo viene con Python> = 2.5, y que no va a manejar listas infinitamente recursivas (por ejemplo, a = []; a.append(a)).

+1

Bueno, nunca he pensado en infinitas listas recursivas en Python.Es genial ver que incluso se pueden imprimir ;-) –

+0

+1 para infinte recursivas listas. Ahora, vaya a [esta pregunta] (http://stackoverflow.com/q/7674685/188595) y lea sobre ellos. –

1

Una simple verificación recursiva sería suficiente, y volver lo más pronto posible, se supone que la entrada no es una lista o parcialmente en las listas no está vacío

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" 

Puede mejorar aún más para comprobar para la lista recursiva o no la lista de objetos, o puede ser predice vacíos etc.

+2

'isEmpty ([1])' falla, eso es todo un problema (no es realmente útil tener una función para verificar si hay una lista vacía si solo funciona con listas que sabe que están vacías). –

+0

que podría ser una buena lógica para verificar si la lista no está vacía :) –

+0

DelRoth: Anurag parece haber solucionado el problema que comentaste ahora. –

7

código simple, que funciona para cualquier objeto iterable, no sólo enumera:

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

Este código hace que la tan suposición de que todo lo que pueda iterarse contendrá otros elementos, y no debe considerarse una hoja en el "árbol". Si falla un intento de iterar sobre un objeto, entonces no es una secuencia, y por lo tanto, ciertamente no es una secuencia vacía (por lo tanto, se devuelve False). Finalmente, este código hace uso del hecho de que all devuelve True si su argumento es una secuencia vacía.

+2

Capturar todas las excepciones es algo malo que puede causar la ocultación de errores reales en el código. –

+1

@Denis: un punto válido. Ahora se redujo a 'TypeError'. – Stephan202

+2

+1 pero creo que 'map' no se debe usar en Python. 'all (empty (x) for x in seq)' suena mucho mejor para mí ;-) –

9

Si no es necesario para recorrer las listas, más simple es mejor, así que algo como esto funcionará:

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 

Sin embargo, sería bueno para separar la iteración recursiva que lo más probable es reutilizar en otro lugar y comprobar que no devuelve ningún elemento. De esta manera, si el mecanismo de iteración cambia, debe implementar el cambio en un lugar. Por ejemplo, cuando necesita admitir iterables anidados arbitrarios o dictados anidados.

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

Hormigas Asama: ¡Me gusta la simplicidad de su solución lo mejor! He editado tu respuesta y moví la solución simple hacia arriba. ¡Gracias! :-) –

+0

gracias, me ahorraste mucho tiempo buscando ... todos los demás enfoques no funcionaron para mí, excepto el tuyo .. thamks –

Cuestiones relacionadas