2013-08-30 13 views
26

Biorąc pod uwagę listę, czy istnieje sposób na uzyskanie pierwszej wartości innej niż Żadna? A jeśli tak, to w jaki sposób można to osiągnąć?Pierwsze pierwsze nie Brak wartości z listy

Na przykład mam:

  • a = objA.addreses.country.code
  • b = objB.country.code
  • c = None
  • d = 'CA'

W tym przypadku, jeśli jest brak, wtedy chciałbym dostać b. Jeśli a i b są oba Brak, chciałbym dostać d.

Obecnie robię coś na wzór (((a or b) or c) or d), czy jest inny sposób?

Odpowiedz

62

Można użyć next():

>>> a = [None, None, None, 1, 2, 3, 4, 5] 
>>> next(item for item in a if item is not None) 
1 

Jeśli lista zawiera tylko Nones będzie rzucać StopIteration wyjątek. Jeśli chcesz mieć wartość domyślną w tym przypadku, to zrobić:

>>> a = [None, None, None] 
>>> next((item for item in a if item is not None), 'All are Nones') 
All are Nones 
+3

Dodałbym polecenie 'try:' z wyjątkiem StopIteration: 'do obsługi list zawierających tylko pozycje Brak. Ale to wspaniała odpowiedź. – Germano

+1

@Germano zaktualizował odpowiedź, sprawdź. Przy okazji, odpowiedź Jona powinna zostać zaakceptowana - jako pierwszy zaproponował rozwiązanie dla list "tylko". – alecxe

+0

w rzeczywistości myślę, że odpowiedź Jona jest niepoprawna: zwraca tylko wartość "Prawda" lub "Fałsz", a nie pierwsza pozycja "Brak" na liście. – Germano

4

Adapt jedną z następujących opcji (można jedno-liner to jeśli chcesz):

values = (a, b, c, d) 
not_None = (el for el in values if el is not None) 
value = next(not_None, None) 

Trwa to pierwszy niekomunistyczny None zamiast tego lub zwraca None.

+0

Nie rozumiem. Czy to nie będzie drukowanie tylko 'True' lub' False'? – thefourtheye

+0

@ thefourtheye yes - miał brzęk mózgu ... dzięki za wskazanie tego –

2

first_true jest itertools przepis znaleźć w Python 3 docs:

def first_true(iterable, default=False, pred=None): 
    """Returns the first true value in the iterable. 

    If no true value is found, returns *default* 

    If *pred* is not None, returns the first item 
    for which pred(item) is true. 

    """ 
    # first_true([a,b,c], x) --> a or b or c or x 
    # first_true([a,b], x, f) --> a if f(a) else b if f(b) else x 
    return next(filter(pred, iterable), default) 

One mogą zdecydować się na wprowadzenie tego ostatniego przepisu lub importować more_itertools, bibliotekę, że statki z itertools receptur i nie tylko:

> pip install more_itertools 

Użyj:

import more_itertools as mit 

a = [None, None, None, 1, 2, 3, 4, 5] 
mit.first_true(a, pred=lambda x: x is not None) 
# 1 

a = [None, None, None] 
mit.first_true(a, default="All are None", pred=lambda x: x is not None) 
# 'All are None' 

Dlaczego używać predykatu?

"Pierwszy element inny niż None" to nie to samo co element "pierwszy True", np. [None, None, 0] gdzie 0 jest pierwszym non-None, ale nie jest pierwszym elementem o numerze True. Predykat pozwala na użycie first_true, zapewniając, że każdy pierwszy widoczny, nie-żaden, element falsey w iteracji jest nadal zwracany (na przykład 0, False) zamiast domyślnego.

a = [None, None, None, False] 
mit.first_true(a, default="All are None", pred=lambda x: x is not None) 
# 'False'