Jak zastosować operator logiczny do wszystkich elementów na liście w Pythonie

90

Mam listę wartości logicznych w Pythonie. Chcę je ORAZ (lub LUB lub NIE) i otrzymać wynik. Poniższy kod działa, ale nie jest zbyt pythonowy.

def apply_and(alist):
 if len(alist) > 1:
     return alist[0] and apply_and(alist[1:])
 else:
     return alist[0]

Wszelkie sugestie, jak uczynić go bardziej pytonicznym, mile widziane.

Robert Christie
źródło

Odpowiedzi:

176

Logiczne anddla wszystkich elementów w a_list:

all(a_list)

Logiczne ordla wszystkich elementów w a_list:

any(a_list)

Jeśli czujesz się kreatywny, możesz również:

import operator
def my_all(a_list):
  return reduce(operator.and_, a_list, True)

def my_any(a_list):
  return reduce(operator.or_, a_list, False)

pamiętaj, że nie są one oceniane w zwarciu, podczas gdy wbudowane są ;-)

inny zabawny sposób:

def my_all_v2(a_list):
  return len(filter(None,a_list)) == len(a_list)

def my_any_v2(a_list):
  return len(filter(None,a_list)) > 0

i jeszcze jeden:

def my_all_v3(a_list):
  for i in a_list:
    if not i:
      return False
  return True

def my_any_v3(a_list):
  for i in a_list:
    if i:
      return True
  return False

i moglibyśmy iść cały dzień, ale tak, pythonowym sposobem jest użycie alli any:-)

Nawiasem mówiąc, Python nie ma ograniczonej eliminacji rekurencji, więc nie próbuj bezpośrednio tłumaczyć kodu LISP ;-)

fortran
źródło
8
operator.and_ jest bitowym i operatorem &, a nie logicznym i.
Ants Aasma
1
na szczęście True i False (zgodnie z oczekiwaniami op) są rzutowane odpowiednio na 1 i 0, więc operatory bitowe działają jako logiczne ^ _ ^
fortran
6
Wyjaśniłem wiele zbędnych wersji, ale nie podałem składni dla właściwej odpowiedzi.
jwg
2
nie zgadzam się z czymkolwiek chcesz, jest to w FAQ: stackoverflow.com/privileges/vote-down
fortran
2
Zauważ, że reduce()jest functoolsod czasu Pythona 3.0
Duncan WP
33

ANDing i ORing są łatwe:

>>> some_list = [True] * 100
# OR
>>> any(some_list)
True
#AND
>>> all(some_list)
True
>>> some_list[0] = False
>>> any(some_list)
True
>>> all(some_list)
False

Notowanie jest również dość łatwe:

>>> [not x for x in some_list]
[True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False]

Oczywiście sposób wykorzystania tych wyników może wymagać interesujących zastosowań twierdzenia DeMorgana.

Jason Baker
źródło
4
Jeśli chcesz krótkiego opisu wariantu nie, po prostu użyj wyrażeń generatora: all(not x for x in some_list)(ale to to samo, co not any(some_list)(całkiem naturalne wyrażenie, co?)).
u0b34a0f6ae
16

Reduce może to zrobić:

reduce(lambda a,b: a and b, alist, True)

Jak wspomniano w Fortran, wszystko jest najbardziej zwięzłe. Ale skróć odpowiedzi do bardziej ogólnego pytania "Jak zastosować operator logiczny do wszystkich elementów na liście Pythona?"

Frank Krueger
źródło
4
redukcja nie odchodzi, AFAIK. jest przenoszony do modułu functools, z poprzedniej pozycji w globalnej przestrzeni nazw
Eli Bendersky,
1
@eliben: Po co mówić o Pythonie 3 w czasie przyszłym? Redukcja wciąż tam jest . reducejest functools.reduce w Pythonie 3
u0b34a0f6ae
Jeśli usuniesz , True, ta odpowiedź będzie jedyną faktycznie równoważną kodowi pytania, dla list innych niż logiczne.
Thomas Ahle
10

Idiomem takich operacji jest użycie reducefunkcji (globalnej w Pythonie 2.X, w module functoolsw Pythonie 3.X) z odpowiednim operatorem binarnym pobranym z operatormodułu lub zakodowanym jawnie. W twoim przypadku to jestoperator.and_

reduce(operator.and_, [True, True, False])
Eli Bendersky
źródło
4

Oto inne rozwiązanie:

def my_and(a_list):
    return not (False in a_list)

def my_or(a_list):
    return True in a_list

Operacja AND na wszystkich elementach zwróci True, jeśli wszystkie elementy są True, stąd na liście nie ma False. ORing jest podobny, ale powinien zwrócić True, jeśli na liście znajduje się co najmniej jedna wartość True.

Xarts
źródło
0

Jak pokazują inne odpowiedzi, istnieje wiele sposobów wykonania tego zadania. Oto kolejne rozwiązanie wykorzystujące funkcje z biblioteki standardowej:

from functools import partial

apply_and = all
apply_or = any
apply_not = partial(map, lambda x: not x)

if __name__ == "__main__":
    ls = [True, True, False, True, False, True]
    print "Original: ", ls
    print "and: ", apply_and(ls)
    print "or: ", apply_or(ls)
    print "not: ", apply_not(ls)
mipadi
źródło