Eu tenho uma lista que consiste em como 20000 listas. Eu uso o terceiro elemento de cada lista como uma bandeira. Quero fazer algumas operações nesta lista, desde que pelo menos o sinalizador de um elemento seja 0, é como:
my_list = [["a", "b", 0], ["c", "d", 0], ["e", "f", 0], .....]
No começo, todos os sinalizadores são 0. Uso um loop while para verificar se pelo menos o sinalizador de um elemento é 0:
def check(list_):
for item in list_:
if item[2] == 0:
return True
return False
Se check(my_list)
retornar True
, continuarei trabalhando na minha lista:
while check(my_list):
for item in my_list:
if condition:
item[2] = 1
else:
do_sth()
Na verdade, eu queria remover um elemento em my_list enquanto iterava sobre ele, mas não tenho permissão para remover itens enquanto iteramos sobre ele.
My_list original não tinha sinalizadores:
my_list = [["a", "b"], ["c", "d"], ["e", "f"], .....]
Como não consegui remover elementos enquanto iterava sobre ele, inventei esses sinalizadores. Mas o my_list
contém muitos itens, e o while
loop lê todos eles em cada for
loop e consome muito tempo! Você tem alguma sugestão?
fonte
None
ou à[]
medida que itera na lista, em vez de removê-los. Verificar a lista inteira com 'check () `repetindo todos os itens antes de cada passagem no loop interno é uma abordagem muito lenta.Respostas:
A melhor resposta aqui é usar
all()
, que é a base para esta situação. Combinamos isso com uma expressão de gerador para produzir o resultado desejado de forma limpa e eficiente. Por exemplo:Observe que
all(flag == 0 for (_, _, flag) in items)
é diretamente equivalente aall(item[2] == 0 for item in items)
, é apenas um pouco mais agradável de ler neste caso.E, para o exemplo de filtro, uma compreensão da lista (é claro, você pode usar uma expressão geradora, quando apropriado):
Se você deseja verificar pelo menos um elemento é 0, a melhor opção é usar o
any()
que for mais legível:fonte
all()
eany()
curto-circuito, se, por exemplo, o primeiro valor na mina for avaliadoFalse
,all()
falhará e não verificará mais nenhum valor, retornandoFalse
. Seu exemplo fará o mesmo, exceto que ele gerará a lista inteira de comparações primeiro, o que significa muito processamento para nada.Se você deseja verificar se algum item da lista viola uma condição, use
all
:Para remover todos os elementos que não correspondem, use
filter
fonte
[...]
,all(...)
pois ele pode criar um gerador em vez de uma lista, que não apenas economiza dois caracteres, mas também economiza tempo e memória. Ao usar geradores, apenas um item será calculado por vez (os resultados anteriores serão descartados porque não são mais usados) e, se algum deles ocorrerFalse
, o gerador interromperá o cálculo do restante.Você pode usar as ferramentas do itertools desse jeito, ele será interrompido assim que uma condição for atendida e falhar na sua declaração. O método oposto seria suspenso
fonte
Outra maneira de usar
itertools.ifilter
. Isso verifica a veracidade e o processo (usandolambda
)Amostra-
fonte
dessa maneira é um pouco mais flexível do que usar
all()
:ou mais sucintamente:
fonte
all_zeros = False in [x[2] == 0 for x in my_list]
ou mesmo0 in [x[2] for x in my_list]
e correspondentementeany_zeros
? Realmente não vejo nenhuma melhoria notávelall()
.all_zeros = False in [x[2] == 0 for x in my_list]
avalia paraFalse
, enquanto a minha avalia paraTrue
. Se você mudar para,all_zeros = not (False in [x[2] == 0 for x in my_list])
então é equivalente ao meu. E0 in [x[2] for x in my_list]
obviamente só vai funcionarany_zeros
. Mas eu gosto da concisão da sua ideia, por isso vou atualizar a minha resposta