2013-03-13 37 views
45

Giả sử rằng tôi có một danh sách có số lượng lớn các mục.python: lấy số lượng mục từ danh sách (chuỗi) với điều kiện nhất định

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

Tôi muốn nhận được số lượng mục từ danh sách đó, trong đó 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 my_condition() danh sách lọc cũng có số lượng lớn các mặt hàng, tôi nghĩ rằng tạo danh sách mới cho kết quả lọc chỉ là sự lãng phí bộ nhớ. Để đạt 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 để đạt được số 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?

Xin cảm ơn trước.

+3

Lựa chọn giữa máy phát và danh sách là lựa chọn giữa thời gian thực hiện và mức tiêu thụ bộ nhớ. Bạn sẽ ngạc nhiên về mức độ thường xuyên của các kết quả truy cập trực quan nếu bạn cấu hình mã. Tối ưu hóa sớm là gốc rễ của mọi điều ác. –

Trả lời

12

Bạn muốn có một generator comprehension thay vì 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 và phát biểu rõ ràng trông hơi hơn Pythonic).

Lưu ý rằng, mặc dù nó không rõ ràng từ ví dụ sum, bạn có thể soạn thảo sự hiểu biết của máy phát 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 riêng biệt về khái niệm trong mã mà không cần đánh giá kết quả cuối cùng.

66

Bạn có thể sử dụng một generator expression:

>>> 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ế là int(True) == 1.

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

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

Thêm vào vấn đề, nó sử dụng thực tế là 'True + True == 2' – mgilson

+1

@mgilson: Tôi không nghĩ rằng nó bao giờ tính toán -' bắt đầu' mặc định là 0, vì vậy phần bổ sung đầu tiên là 'True + 0', không? – DSM

+4

Có. Có lẽ tôi nên rõ ràng hơn ... Nó không quan trọng những gì 'int (True)' là. 'int (" 1 ") == 1' cũng vậy, nhưng điều đó không có nghĩa là bạn có thể làm' "1" + 0'. Điều quan trọng là làm thế nào python đánh giá 'số nguyên + True' hoặc' số nguyên + Sai'. – mgilson

1
from itertools import imap 
sum(imap(my_condition, l)) 
3

bạn có thể làm một cái gì đó như:

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

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

4

này cũng có thể được thực hiện bằng reduce nế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ỉ làm 1 đường chuyền và không có danh sách trung gian được tạo ra.

Các vấn đề liên quan