Python: получить количество элементов из списка (последовательность) с определенным условием
Предполагая, что у меня есть список с огромным количеством элементов.
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
Есть ли какой-либо функциональный стиль для достижения, чтобы получить # элементов, удовлетворяющих определенному условию без создания временного списка?
Спасибо заранее.
Ответы
Ответ 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
Ответ 2
Вы хотите понимание генератора, а не список здесь.
Например,
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
Прохладная вещь об этом методе заключается в том, что вы можете указать концептуально отдельные шаги в коде, не заставляя оценивать и хранить в памяти до тех пор, пока не будет оценен конечный результат.
Ответ 3
Это также можно сделать, используя reduce
, если вы предпочитаете функциональное программирование
reduce(lambda count, i: count + my_condition(i), l, 0)
Таким образом, вы выполняете только 1 проход, а промежуточный список не генерируется.
Ответ 4
вы можете сделать что-то вроде:
l = [1,2,3,4,5,..]
count = sum(1 for i in l if my_condition(i))
который просто добавляет 1 для каждого элемента, который удовлетворяет условию.
Ответ 5
from itertools import imap
sum(imap(my_condition, l))
Ответ 6
У меня была схожая проблема и решить ее с помощью генераторов.
Я также думаю, что этот вопрос может помочь вам:
Фильтрация списков: понимание списка по сравнению с lambda + filter