Zakładając, że mam listę z ogromną liczbą pozycji.
l = [ 1, 4, 6, 30, 2, ... ]
Chcę uzyskać liczbę pozycji z tej listy, dla których pozycja powinna spełniać określony warunek. Moją pierwszą myślą było:
count = len([i for i in l if my_condition(l)])
Ale jeśli lista filtrowana my_condition () ma również dużą liczbę elementów, myślę, że tworzenie nowej listy dla przefiltrowanych wyników jest po prostu stratą pamięci. Dla wydajności, IMHO, powyższe wezwanie nie może być lepsze niż:
count = 0
for i in l:
if my_condition(l):
count += 1
Czy jest jakiś funkcjonalny sposób na uzyskanie liczby elementów spełniających określony warunek bez generowania listy tymczasowej?
Z góry dziękuję.
Odpowiedzi:
Możesz użyć wyrażenia generatora :
>>> l = [1, 3, 7, 2, 6, 8, 10] >>> sum(1 for i in l if i % 4 == 3) 2
lub nawet
>>> sum(i % 4 == 3 for i in l) 2
który wykorzystuje fakt, że
int(True) == 1
.Alternatywnie możesz użyć
itertools.imap
(python 2) lub po prostumap
(python 3):>>> def my_condition(x): ... return x % 4 == 3 ... >>> sum(map(my_condition, l)) 2
źródło
start
domyślnie 0, więc pierwszy dodatek brzmiTrue + 0
, nie?int(True)
jest.int("1") == 1
ale to nie znaczy, że możesz to zrobić"1" + 0
. Liczy się sposób, w jaki Python oceniainteger + True
lubinteger + False
.bool
jest to podklasaint
, więc możesz łatwo dodawać boole i ints (True
o wartości 1 iFalse
0).int(True) == 1
, wspominając , ale twój punkt widzeniaint("1") == 1
dowodzi, że skrócenie tego w ten sposób może oznaczać rzeczy, które nie są prawdą.Chcesz raczej zrozumienia generatora niż listy tutaj.
Na przykład,
l = [1, 4, 6, 7, 30, 2] def my_condition(x): return x > 5 and x < 20 print sum(1 for x in l if my_condition(x)) # -> 2 print sum(1 for x in range(1000000) if my_condition(x)) # -> 14
Lub użyj
itertools.imap
(chociaż wydaje mi się, że jawna lista i wyrażenia generatora wyglądają nieco bardziej w Pythonie).Zauważ, że chociaż nie jest to oczywiste z
sum
przykładu, możesz ładnie komponować wyrażenia generatora. Na przykład,inputs = xrange(1000000) # In Python 3 and above, use range instead of xrange odds = (x for x in inputs if x % 2) # Pick odd numbers sq_inc = (x**2 + 1 for x in odds) # Square and add one print sum(x/2 for x in sq_inc) # Actually evaluate each one # -> 83333333333500000
Fajną rzeczą w tej technice jest to, że można określić koncepcyjnie oddzielne kroki w kodzie bez wymuszania oceny i przechowywania w pamięci do czasu oceny końcowego wyniku.
źródło
Można to również zrobić za pomocą,
reduce
jeśli wolisz programowanie funkcjonalnereduce(lambda count, i: count + my_condition(i), l, 0)
W ten sposób wykonujesz tylko 1 przebieg i nie jest generowana lista pośrednia.
źródło
możesz zrobić coś takiego:
l = [1,2,3,4,5,..] count = sum(1 for i in l if my_condition(i))
co po prostu dodaje 1 do każdego elementu spełniającego warunek.
źródło
from itertools import imap sum(imap(my_condition, l))
źródło
imap
nie jest dostępny w aktualnym Pythonie.