python: lấy số lượng mục từ danh sách (chuỗi) với điều kiện nhất định


84

Giả sử rằng tôi có một danh sách với số lượng lớn các mục.

l = [ 1, 4, 6, 30, 2, ... ]

Tôi muốn lấy số mục từ danh sách đó, trong đó một mục phải thỏa mãn điều kiện nhất định. Suy nghĩ đầu tiên của tôi là:

count = len([i for i in l if my_condition(l)])

Nhưng nếu danh sách được lọc my_condition () cũng có số lượng lớn các mục, tôi nghĩ rằng việc tạo danh sách mới cho kết quả được lọc chỉ lãng phí bộ nhớ. Đối với hiệu quả, IMHO, cuộc gọi trên không thể tốt hơn:

count = 0
for i in l:
    if my_condition(l):
        count += 1

Có cách nào theo kiểu chức năng để đạt được # mục thỏa mãn điều kiện nhất định mà không tạo danh sách tạm thời không?

Cảm ơn trước.


3
Sự lựa chọn giữa trình tạo và danh sách là sự lựa chọn giữa thời gian thực thi và mức tiêu thụ bộ nhớ. Bạn sẽ ngạc nhiên về mức độ thường xuyên các kết quả không trực quan nếu bạn lập hồ sơ mã. Tối ưu hóa sớm là gốc rễ của mọi điều xấu.
Paulo Scardine

Câu trả lời:


102

Bạn có thể sử dụng một biểu thức trình tạo :

>>> l = [1, 3, 7, 2, 6, 8, 10]
>>> sum(1 for i in l if i % 4 == 3)
2

hoặc thậm chí

>>> sum(i % 4 == 3 for i in l)
2

trong đó sử dụng thực tế rằng int(True) == 1.

Ngoài ra, bạn có thể sử dụng itertools.imap(python 2) hoặc đơn giản map(python 3):

>>> def my_condition(x):
...     return x % 4 == 3
... 
>>> sum(map(my_condition, l))
2

1
@mgilson: Tôi không nghĩ rằng nó đã bao giờ thực hiện phép tính đó - startmặc định là 0, vì vậy bổ sung đầu tiên là True + 0, không?
DSM

4
Đúng. Có lẽ tôi nên rõ ràng hơn ... Nó không quan trọng int(True)là gì . int("1") == 1cũng được, nhưng điều đó không có nghĩa là bạn có thể làm được "1" + 0. Điều quan trọng là cách python đánh giá integer + Truehoặc integer + False.
mgilson

2
@mgilson: hmm, được rồi, bạn đã thuyết phục được tôi.
DSM

4
Vấn đề là đó boollà một lớp con của intvà bạn nên bạn có thể dễ dàng thêm các bools và int (với Truegiá trị là 1 và Falsecó giá trị là 0).
mgilson

Chà, đó là những gì tôi muốn đề cập int(True) == 1, nhưng quan điểm của bạn int("1") == 1chứng minh rằng viết tắt nó theo cách đó có thể ngụ ý những điều không đúng.
DSM

21

Bạn muốn hiểu rõ về trình tạo hơn là một danh sách ở đây.

Ví dụ,

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

Hoặc sử dụng itertools.imap(mặc dù tôi nghĩ rằng danh sách rõ ràng và các biểu thức trình tạo trông giống Pythonic hơn).

Lưu ý rằng, mặc dù nó không rõ ràng từ sumví dụ, nhưng bạn có thể soạn thảo phần hiểu của trình tạo một cách độc đáo. Ví dụ,

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

Điều thú vị về kỹ thuật này là bạn có thể chỉ định các bước tách biệt về mặt khái niệm trong mã mà không buộc phải đánh giá và lưu trữ trong bộ nhớ cho đến khi kết quả cuối cùng được đánh giá.


10

Điều này cũng có thể được thực hiện bằng cách sử dụng reducenếu bạn thích lập trình chức năng

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

Bằng cách này, bạn chỉ thực hiện 1 lần và không có danh sách trung gian nào được tạo.


7

bạn có thể làm điều gì đó như:

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

mà chỉ thêm 1 cho mỗi phần tử thỏa mãn điều kiện.


Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.