2012-05-19 7 views
97

Mam listę zawierającą około 20000 list. Używam trzeciego elementu każdej listy jako flagi. Chcę zrobić kilka operacji na tej liście tak długo jak flaga przynajmniej jeden element jest 0, to jak:Jak sprawdzić, czy wszystkie elementy listy pasują do warunku?

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

Na początku wszystkie flagi są 0. użyć pętli while, aby sprawdzić, czy co najmniej jeden element na Flaga jest 0:

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

If check(my_list) powraca True, to będę kontynuował pracę na mojej liście:

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

Właściwie chciałem usunąć element my_list jak powtórzyć nad nim, ale nie wolno mi usuwać przedmiotu, ponieważ go powtarzam.

Original my_list nie mają flagi:

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

Ponieważ nie mogę usunąć elementy jak potwierdzili nad nim, wymyśliłem te flagi. Ale my_list zawiera wiele elementów, a pętla while odczytuje je wszystkie w każdej pętli for i zajmuje dużo czasu! Masz jakieś sugestie?

+2

wygląda jak struktura danych nie jest idealnym rozwiązaniem dla Twojego problemu.Jeśli wytłumaczysz kontekst nieco bardziej, może będziemy mogli zaproponować coś bardziej odpowiedniego. – uselpa

+0

Być może możesz zamienić elementy na "Brak" lub "[]" podczas iteracji na liście zamiast ich usuwania. Sprawdzanie całej listy za pomocą "check()" iteracji wszystkich elementów przed każdym przejściem do wewnętrznej pętli jest bardzo powolnym podejściem. – martineau

Odpowiedz

211

Najlepszą odpowiedzią jest tutaj użycie all(), która jest wbudowana w tę sytuację. Łączymy to z generator expression, aby uzyskać czysty i wydajny efekt. Na przykład:

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

I za jego przykładem filtra, lista zrozumieniem:

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

Jeśli chcesz sprawdzić, co najmniej jeden element jest 0, to lepszym rozwiązaniem jest użycie any() który jest bardziej czytelny:

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

Moja wina na temat użycia lambda, wszystko Pythona nie przyjmuje funkcji jako pierwszy argument, jak Haskell et. al., zmieniłem również moją odpowiedź na zrozumienie list. :) –

+2

@HampusNilsson Zrozumienie listy nie jest tożsame z wyrażeniem generatora. Jako 'all()' i 'any()' zwarcie, jeśli na przykład pierwsza wartość w kopalni zostanie obliczona jako "Fałsz", 'wszystko()' zawiedzie i nie sprawdzi więcej wartości, zwracając 'False'. Twój przykład zrobi to samo, z tym, że najpierw wygeneruje całą listę porównań, co oznacza dużo przetwarzania za darmo. –

5

Możesz używać takertools tak tak, zatrzyma się, gdy spełniony jest warunek, który nie powiedzie się. Przeciwieństwem metodą byłoby dropwhile

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

Jeśli chcesz sprawdzić, czy każdy element na liście jest niezgodny zastosowanie warunek 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) 

Aby usunąć wszystkie elementy nie pasujące, użyj filter

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

ten sposób jest nieco bardziej elastyczne niż przy użyciu 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

Inny sposób używania itertools.ifilter. To sprawdza truthiness i proces (używając lambda)

Sample-

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