2012-05-19 41 views
97

Tengo una lista compuesta por 20000 listas similares. Yo uso el tercer elemento de cada lista como una bandera. Quiero hacer algunas operaciones en esta lista, siempre y cuando la bandera de al menos un elemento es 0, es como:¿Cómo comprobar si todos los elementos de una lista coinciden con una condición?

my_list = [["a", "b", 0], ["c", "d", 0], ["e", "f", 0], .....] 

Al principio todas las banderas son 0. Puedo usar un bucle while para comprobar si al menos un elemento de bandera es 0:

def check(lista): 
    for item in lista: 
     if item[2] == 0: 
      return True 
    return False 

If check(my_list) vuelve True, a continuación, sigo trabajando en mi lista:

while check(my_list): 
    for item in my_list: 
     if condition: 
      item[2] = 1 
     else: 
      do_sth() 

realidad quería para eliminar los elementos de my_list como iterado sobre él, pero no puedo eliminar el elemento mientras lo repito.

my_list original no tenía banderas:

my_list = [["a", "b"], ["c", "d"], ["e", "f"], .....] 

Como no podía quitar elementos como se repiten a lo largo, inventé estas banderas. Pero el my_list contiene muchos elementos, y el bucle while los lee todos en cada bucle for, ¡y consume mucho tiempo! ¿Tienes alguna sugerencia?

+2

se parece a la estructura de datos no es la ideal para su problema.Si explicó el contexto un poco más, tal vez podríamos sugerir algo más apropiado. – uselpa

+0

Tal vez podría reemplazar los elementos con 'Ninguno' o' [] 'mientras itera sobre la lista en lugar de eliminarlos. Comprobar la lista completa con 'check()' iterar sobre todos los elementos antes de cada pasada en el bucle interno es un enfoque muy lento. – martineau

Respuesta

211

La mejor respuesta aquí es usar all(), que es el built-in para esta situación. Combinamos esto con un generator expression para producir el resultado que desea de manera limpia y eficiente. Por ejemplo:

>>> items = [[1, 2, 0], [1, 2, 0], [1, 2, 0]] 
>>> all(item[2] == 0 for item in items) 
True 
>>> items = [[1, 2, 0], [1, 2, 1], [1, 2, 0]] 
>>> all(item[2] == 0 for item in items) 
False 

Y, por su ejemplo de filtro, una lista por comprensión:

>>> [x for x in items if x[2] == 0] 
[[1, 2, 0], [1, 2, 0]] 

Si desea comprobar al menos un elemento es 0, la mejor opción es utilizar any() que es más legible:

>>> any(item[2] == 0 for item in items) 
True 
+0

Mi error en el uso de lambda, Python's all no acepta una función como primer argumento como Haskell et. al., cambié mi respuesta a una lista de comprensión también. :) –

+2

@HampusNilsson Una comprensión de lista no es lo mismo que una expresión de generador. Como 'all()' y 'any()' cortocircuito, si, por ejemplo, el primer valor en la mina se evalúa como 'False',' all() 'fallará y no comprobará más valores, devolviendo' False'. Su ejemplo hará lo mismo, excepto que generará la lista completa de comparaciones primero, lo que significa mucho procesamiento para nada. –

5

Puede usar las tareas de itertools de este modo, se detendrá una vez que se cumple una condición que no cumple con su declaración. El método contrario sería dropwhile

for x in itertools.takewhile(lambda x: x[2] == 0, list) 
    print x 
3

Si desea comprobar si cualquier elemento de la lista viola un uso condición all:

if all([x[2] == 0 for x in lista]): 
    # Will run if all elements in the list has x[2] = 0 (use not to invert if necessary) 

Para eliminar todos los elementos que no coincidan, utilice filter

# Will remove all elements where x[2] is 0 
listb = filter(lambda x: x[2] != 0, listb) 
0

esta manera es un poco más flexible que el uso de all():

my_list = [[1, 2, 0], [1, 2, 0], [1, 2, 0]] 
all_zeros = False if False in [x[2] == 0 for x in my_list] else True 
any_zeros = True if True in [x[2] == 0 for x in my_list] else False 
0

Otra forma de usar itertools.ifilter. Este truthiness cheques y el proceso (usando lambda)

Sample

for x in itertools.ifilter(lambda x: x[2] == 0, my_list): 
    print x 
Cuestiones relacionadas