Mam listę składającą się z około 20000 list. Używam trzeciego elementu każdej listy jako flagi. Chcę wykonać kilka operacji na tej liście, o ile flaga przynajmniej jednego elementu ma wartość 0, to jest tak:
my_list = [["a", "b", 0], ["c", "d", 0], ["e", "f", 0], .....]
Na początku wszystkie flagi mają wartość 0. Używam pętli while, aby sprawdzić, czy flaga przynajmniej jednego elementu ma wartość 0:
def check(list_):
for item in list_:
if item[2] == 0:
return True
return False
Jeśli check(my_list)
wróci True
, kontynuuję pracę nad moją listą:
while check(my_list):
for item in my_list:
if condition:
item[2] = 1
else:
do_sth()
Właściwie chciałem usunąć element z mojej_listy podczas iteracji, ale nie mogę usuwać elementów podczas iteracji.
Oryginalna moja lista nie miała flag:
my_list = [["a", "b"], ["c", "d"], ["e", "f"], .....]
Ponieważ nie mogłem usunąć elementów podczas iteracji, wymyśliłem te flagi. Ale my_list
zawiera wiele elementów, a while
pętla odczytuje je wszystkie w każdej for
pętli i zajmuje dużo czasu! Masz jakieś sugestie?
źródło
None
lub[]
podczas iteracji na liście zamiast je usuwać. Sprawdzanie całej listy za pomocą „check ()” iterującego wszystkie elementy przed każdym przejściem w wewnętrznej pętli jest bardzo powolnym podejściem.Odpowiedzi:
Najlepszą odpowiedzią jest użycie
all()
wbudowanego w tej sytuacji. Łączymy to z wyrażeniem generatora, aby uzyskać pożądany efekt w sposób czysty i wydajny. Na przykład:Zauważ, że
all(flag == 0 for (_, _, flag) in items)
jest to bezpośrednio równoważneall(item[2] == 0 for item in items)
, w tym przypadku jest tylko trochę przyjemniej czytać.I, na przykład filtru, zrozumienie listy (oczywiście, w razie potrzeby można użyć wyrażenia generatora):
Jeśli chcesz sprawdzić, że przynajmniej jeden element ma wartość 0, lepszą opcją jest użycie
any()
bardziej czytelnego:źródło
all()
iany()
zwarcie, jeśli, na przykład, pierwsza wartość na mojej oszacuje doFalse
,all()
zawiedzie i nie będzie sprawdzać kolejnych wartości, powracającFalse
. Twój przykład zrobi to samo, tyle że najpierw wygeneruje całą listę porównań, co oznacza dużo przetwarzania za nic.Jeśli chcesz sprawdzić, czy jakikolwiek element na liście narusza warunek, użyj
all
:Aby usunąć wszystkie niepasujące elementy, użyj
filter
źródło
[...]
wall(...)
ponieważ może następnie stworzyć generator zamiast listy, która nie tylko oszczędza dwie postacie, ale także oszczędność czasu i pamięci. Używając generatorów, tylko jeden element będzie obliczany na raz (poprzednie wyniki zostaną upuszczone, ponieważ nie są już używane), a jeśli którykolwiek z nich się okażeFalse
, generator przestanie obliczać resztę.Możesz użyć taktu itertools w taki sposób, że zatrzyma się on, gdy zostanie spełniony warunek, który nie powiedzie się w twoim oświadczeniu. Przeciwna metoda byłaby kroplowa
źródło
Kolejny sposób użycia
itertools.ifilter
. To sprawdza prawdziwość i proces (używanielambda
)Próba-
źródło
ten sposób jest nieco bardziej elastyczny niż używanie
all()
:lub bardziej zwięźle:
źródło
all_zeros = False in [x[2] == 0 for x in my_list]
a nawet0 in [x[2] for x in my_list]
i odpowiednio zaany_zeros
? Tak naprawdę nie widzę żadnej znaczącej poprawyall()
.all_zeros = False in [x[2] == 0 for x in my_list]
oceniaFalse
, a moja ocenia naTrue
. Jeśli zmienisz na,all_zeros = not (False in [x[2] == 0 for x in my_list])
to będzie to odpowiednik mojego. I0 in [x[2] for x in my_list]
oczywiście będzie pracował tylko dlaany_zeros
. Ale podoba mi się zwięzłość twojego pomysłu, dlatego zaktualizuję swoją odpowiedź