Предполагая, что у меня есть список с огромным количеством элементов.
l = [ 1, 4, 6, 30, 2, ... ]
Я хочу получить количество элементов из этого списка, где элемент должен удовлетворять определенному условию. Моя первая мысль была:
count = len([i for i in l if my_condition(l)])
Но если отфильтрованный список my_condition () также имеет большое количество элементов, я думаю, что создание нового списка для отфильтрованного результата - просто пустая трата памяти. Для эффективности, IMHO, вышеупомянутый вызов не может быть лучше, чем:
count = 0
for i in l:
if my_condition(l):
count += 1
Есть ли какой-либо функциональный способ получить количество элементов, удовлетворяющих определенному условию, без создания временного списка?
Заранее спасибо.
Ответы:
Вы можете использовать выражение генератора :
>>> l = [1, 3, 7, 2, 6, 8, 10] >>> sum(1 for i in l if i % 4 == 3) 2
или даже
>>> sum(i % 4 == 3 for i in l) 2
который использует тот факт, что
int(True) == 1
.В качестве альтернативы вы можете использовать
itertools.imap
(python 2) или простоmap
(python 3):>>> def my_condition(x): ... return x % 4 == 3 ... >>> sum(map(my_condition, l)) 2
источник
start
умолчанию 0, поэтому первое добавлениеTrue + 0
, нет?int(True)
.int("1") == 1
также, но это не значит, что вы можете это сделать"1" + 0
. Важно то, как python оцениваетinteger + True
илиinteger + False
.bool
это подклассint
and you, поэтому вы можете легко добавлять bools и int (соTrue
значением 1 иFalse
значением 0).int(True) == 1
виду, упомянув , но ваша точка зрения, котораяint("1") == 1
доказывает, что такое сокращение может подразумевать вещи, которые не соответствуют действительности.Здесь вам нужен генератор понимания, а не список.
Например,
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
Или используйте
itertools.imap
(хотя я думаю, что явные выражения списка и генератора выглядят несколько более Pythonic).Обратите внимание, что, хотя это не очевидно из
sum
примера, вы можете хорошо составить понимание генератора. Например,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
Самое замечательное в этом методе состоит в том, что вы можете определять концептуально отдельные шаги в коде без принудительной оценки и хранения в памяти до тех пор, пока не будет оценен окончательный результат.
источник
Это также можно сделать с помощью,
reduce
если вы предпочитаете функциональное программированиеreduce(lambda count, i: count + my_condition(i), l, 0)
Таким образом, вы выполняете только 1 проход, и промежуточный список не создается.
источник
вы могли бы сделать что-то вроде:
l = [1,2,3,4,5,..] count = sum(1 for i in l if my_condition(i))
который просто добавляет 1 для каждого элемента, удовлетворяющего условию.
источник
from itertools import imap sum(imap(my_condition, l))
источник
imap
недоступно с текущим Python.