2013-04-30 21 views
5

Tôi cần phải xây dựng một máy phát điện và tôi đã tìm kiếm một cách để rút ngắn này cho vòng lặp vào một dòng duy nhất. Tôi đã thử liệt kê nhưng điều đó không hiệu quả.Có cách nào để rút ngắn biểu thức trình tạo Python này không?

counter=0 
for element in string: 
    if function(element): 
     counter+=1 
     yield counter 
    else: 
     yield counter 
+1

Bạn đang thiếu một 'truy cập = 0', hoặc được coi là đóng cửa xung quanh bất cứ điều gì 'counter' nằm trong mã ngoài? – abarnert

+0

Phiên bản Python nào? – Blender

+0

Không, tôi đã loại trừ nó ban đầu, nhưng tôi chỉ bao gồm nó. – garlfd

Trả lời

6
counter=0 
for element in string: 
    counter+=bool(function(element)) 
    yield counter 

(Vâng, thêm Booleans để ints hoạt động chính xác như thể True1False0).

Các bool() cuộc gọi duy nhất là cần thiết nếu function() có thể có giá trị trả về khác hơn True, False, 1, và 0.

4

Nếu bạn đang sử dụng Python 3, bạn có thể làm:

from itertools import accumulate 

yield from accumulate(1 if function(x) else 0 for x in string) 

Mặc dù tôi muốn sử dụng Simeon Visser's answer. Trong khi điều này có thể ngắn, nó không phải là ngay lập tức rõ ràng những gì các mã nào.

+0

@jamylak: Bạn không có biến 'counter' ở cuối. – Blender

+0

Điều này sẽ không hoạt động trừ khi 'hàm' trả về một cách rõ ràng 0 và 1. Nếu nó trả về, chẳng hạn' None' hoặc một chuỗi, bạn sẽ nhận được 'TypeError's trên tất cả. Ngay cả khi nó trả về 'True' và' False', giá trị đầu tiên sẽ là 'False' thay vì' 0'. – abarnert

+0

Tôi không chắc chắn những gì "Tôi giả sử' tích lũy' trả về một boolean "có nghĩa là. Nó trả về một trình lặp. Và đó là một iterator trên bất kỳ loại addable bạn cung cấp cho nó (hoặc, thay vì, kết quả của việc thêm bất kỳ loại nào bạn cho nó - không hoàn toàn giống nhau, bởi vì, ví dụ, 'False + True == 1', hoặc, cũ hơn Python, '(1 << 31) + (1 << 31) = (1L << 32)'). – abarnert

3

Bạn có thể rút ngắn nó để:

counter=0 
for element in string: 
    if function(element): 
     counter+=1 
    yield counter 
+0

Tôi cần giữ số lượng đang chạy, vì vậy tôi cần phải thực hiện với tuyên bố khác. – garlfd

+2

@garlfd: ​​điều này vẫn mang lại với mọi yếu tố trong chuỗi, nó chỉ cập nhật nó cho một số yếu tố. –

4

Trước tiên, bạn có thể chuyển đổi chuỗi thành một iterator so với giá trị function trở lại:

truths = (function(x) for x in string) 

Sau đó, bạn có thể ánh xạ chúng đến 0s và 1s:

onesandzeroes = (1 if function(x) else 0 for x in string) 

Và sau đó accumulate họ:

running = itertools.accumulate(1 if function(x) else 0 for x in string) 

Lưu ý tài liệu, accumulate đã được thêm vào Python 3.2. Nếu bạn đang sử dụng 2.x, bạn có thể sao chép và dán công thức "Tương đương với" từ tài liệu. (Nếu bạn đang sử dụng 3.0-3.1, bạn có thể làm tương tự, nhưng thực sự, trong trường hợp đó, chỉ cần nâng cấp.)

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