Tengo una lista que consta de como 20000 listas. Yo uso el tercer elemento de cada lista como una bandera. Quiero hacer algunas operaciones en esta lista siempre que al menos el indicador de un elemento sea 0, es como:
my_list = [["a", "b", 0], ["c", "d", 0], ["e", "f", 0], .....]
Al principio, todas las banderas son 0. Uso un ciclo while para verificar si al menos la bandera de un elemento es 0:
def check(list_):
for item in list_:
if item[2] == 0:
return True
return False
Si check(my_list)
regresa True
, entonces sigo trabajando en mi lista:
while check(my_list):
for item in my_list:
if condition:
item[2] = 1
else:
do_sth()
En realidad, quería eliminar un elemento en my_list mientras iteraba sobre él, pero no se me permite eliminar elementos mientras itero sobre él.
My_list original no tenía banderas:
my_list = [["a", "b"], ["c", "d"], ["e", "f"], .....]
Como no podía eliminar elementos mientras lo repetía, inventé estas banderas. Pero my_list
contiene muchos elementos, y el while
ciclo los lee todos en cada for
ciclo, ¡y consume mucho tiempo! ¿Tienes alguna sugerencia?
fuente
None
o[]
mientras itera sobre la lista en lugar de eliminarlos. Verificar la lista completa con 'check ()' iterando sobre todos los elementos antes de cada pasada en el bucle interno es un enfoque muy lento.Respuestas:
La mejor respuesta aquí es usar
all()
, que es el incorporado para esta situación. Combinamos esto con una expresión generadora para producir el resultado que desea de forma limpia y eficiente. Por ejemplo:Tenga en cuenta que
all(flag == 0 for (_, _, flag) in items)
es directamente equivalente aall(item[2] == 0 for item in items)
, es un poco más agradable de leer en este caso.Y, para el ejemplo de filtro, una comprensión de la lista (por supuesto, podría usar una expresión generadora cuando corresponda):
Si desea verificar que al menos un elemento es 0, la mejor opción es usar el
any()
que sea más legible:fuente
all()
yany()
cortocircuito, si, por ejemplo, el primer valor en la mina evalúaFalse
,all()
fallará y no verificará más valores, regresandoFalse
. Su ejemplo hará lo mismo, excepto que generará la lista completa de comparaciones primero, lo que significa mucho procesamiento para nada.Si desea verificar si algún elemento de la lista infringe una condición, utilice
all
:Para eliminar todos los elementos que no coinciden, use
filter
fuente
[...]
en elall(...)
puesto que se puede crear un generador en lugar de una lista, que no sólo le ahorra dos personajes, sino que también ahorra memoria y el tiempo. Al usar generadores, solo se calculará un elemento a la vez (los resultados anteriores se eliminarán porque ya no se usan) y si alguno de ellos resultaFalse
, el generador dejará de calcular el resto.Puede usar el tiempo de itertools de esta manera, se detendrá una vez que se cumpla una condición que falle su declaración. El método opuesto sería droptime
fuente
Otra forma de usar
itertools.ifilter
. Esto verifica la veracidad y el proceso (usandolambda
)Muestra-
fuente
de esta manera es un poco más flexible que usar
all()
:o más sucintamente:
fuente
all_zeros = False in [x[2] == 0 for x in my_list]
o incluso0 in [x[2] for x in my_list]
y correspondientemente paraany_zeros
? Realmente no veo ninguna mejora notableall()
.all_zeros = False in [x[2] == 0 for x in my_list]
evalúa comoFalse
, mientras que la mía se evalúa comoTrue
. Si lo cambia a,all_zeros = not (False in [x[2] == 0 for x in my_list])
entonces es equivalente al mío. Y0 in [x[2] for x in my_list]
obviamente solo va a funcionarany_zeros
. Pero me gusta la concisión de su idea, así que voy a actualizar mi respuesta