python: отримати кількість елементів зі списку (послідовності) з певною умовою


84

Якщо припустити, що у мене є список з величезною кількістю предметів.

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

Чи існує якийсь спосіб у функціональному стилі, щоб отримати # предметів, які відповідають певним умовам, без створення тимчасового списку?

Заздалегідь спасибі.


3
Вибір між генераторами та списками - це вибір між часом виконання та споживанням пам'яті. Ви були б здивовані, як часто результати є інтуїтивно зрозумілими, якщо ви профілюєте код. Передчасна оптимізація - корінь усього зла.
Пауло Скардін

Відповіді:


102

Ви можете використовувати генератор виразу :

>>> 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

1
@mgilson: Я не думаю, що він коли-небудь робить це обчислення - startза замовчуванням 0, тож перше додавання True + 0, ні?
DSM

4
Так. Можливо, я мав би бути більш чітким ... Неважливо, що int(True)є. int("1") == 1також, але це не означає, що ви можете це зробити "1" + 0. Важливо те, як python оцінює integer + Trueабо integer + False.
мгільсон

2
@mgilson: хм, гаразд, ти мене переконав.
DSM

4
Справа в тому, що boolце підклас, intі ви, щоб ви могли легко додавати bools і ints (зі Trueзначенням 1 і Falseзначенням 0).
mgilson

Ну, це те, на що я стикався, згадуючи int(True) == 1, але ваша думка, яка int("1") == 1доводить, що скорочення цього слова може означати речі, які не відповідають дійсності.
DSM

21

Вам потрібне розуміння генератора, а не списку тут.

Наприклад,

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(хоча я думаю, що явні вирази списку та генератора виглядають дещо більш пітонічними).

Зверніть увагу, що, хоча з 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

Найцікавіше в цій техніці полягає в тому, що ви можете вказувати концептуально окремі кроки в коді, не примушуючи оцінку та зберігання в пам'яті, поки не буде оцінений кінцевий результат.


10

Це також можна зробити за допомогою, reduceякщо ви віддаєте перевагу функціональному програмуванню

reduce(lambda count, i: count + my_condition(i), l, 0)

Таким чином ви виконуєте лише 1 прохід і проміжний список не створюється.


7

Ви можете зробити щось на зразок:

l = [1,2,3,4,5,..]
count = sum(1 for i in l if my_condition(i))

який просто додає 1 для кожного елемента, що задовольняє умові.


Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.