2010-04-26 25 views
5

Tôi có một vòng lặp muốn thực thi để cạn kiệt hoặc cho đến khi đạt đến một số giới hạn do người dùng chỉ định. Tôi đã có một cấu trúc trông xấu nhưng tôi dường như không thể tìm thấy một cách thanh lịch hơn để thể hiện nó; có ai không?một cách khác nữa để thể hiện vòng lặp bị ràng buộc có điều kiện?

def ello_bruce(limit=None): 
    for i in xrange(10**5): 
     if predicate(i): 
      if not limit is None: 
       limit -= 1 
       if limit <= 0: 
        break 

def predicate(i): 
    # lengthy computation 
    return True 

Làm tổ thánh! Có phải là một cách tốt hơn. Với mục đích của một ví dụ làm việc, xrange được sử dụng trong đó tôi thường có một trình vòng lặp có độ dài hữu hạn nhưng không xác định (và vị ngữ đôi khi trả về Sai).

+0

Bạn ít nhất có thể kiểm tra xem giới hạn có là Không trước vòng lặp và trả lại nếu có thay vì kiểm tra nó bất kỳ lúc nào vị từ đó là đúng. Điều đó không thực sự làm cho nó trở nên trầm trọng hơn, nhưng nó có thể tiết kiệm rất nhiều tính toán không cần thiết trong vòng lặp của bạn. –

+0

Ông quên đặt hành động thực tế ở đây, nhưng tôi mong đợi giới hạn = Không có nghĩa là "không có giới hạn", không "không làm bất cứ điều gì". –

+0

Lưu ý rằng việc dọn dẹp đơn giản nhất mà bạn có thể thực hiện ở đây là đảo ngược điều kiện: 'nếu không phải là biến vị ngữ (i): tiếp tục', tránh đặt toàn bộ phần còn lại của khối ở mức làm tổ phụ. Điều này áp dụng cho rất nhiều mã, vì vậy nó là một điều tốt để tìm hiểu nói chung. –

Trả lời

11

Có lẽ một cái gì đó như thế này sẽ tốt hơn một chút:

from itertools import ifilter, islice 

def ello_bruce(limit=None): 
    for i in islice(ifilter(predicate, xrange(10**5)), limit): 
     # do whatever you want with i here 
+0

+1 Giải pháp tuyệt vời! –

+0

hoàn hảo, cảm ơn bạn. – msw

+6

Cách nghiền nát này quá nhiều thành một dòng; mã gốc rõ ràng hơn. Nó sẽ giúp rất nhiều để phân chia các tổ ngoài; 'iter = ifilter (predicate, xrange (10 ** 5))' và sau đó 'cho i trong islice (iter, limit)'. –

2

Tôi sẽ xem xét tốt thư viện itertools. Sử dụng điều đó, tôi nghĩ rằng bạn muốn có một cái gì đó giống như ...

# From the itertools examples 
def tabulate(function, start=0): 
    return imap(function, count(start)) 
def take(n, iterable): 
    return list(islice(iterable, n)) 

# Then something like: 
def ello_bruce(limit=None): 
    take(filter(tabulate(predicate)), limit) 
+0

+1 thực sự, mô-đun đó có một số quyền hạn tinh tế (hoặc sự tinh tế mạnh mẽ). – msw

+0

Tôi nghĩ rằng các tham số cho 'take' được đảo ngược, tức là bạn có' def take (n, iterable) ', nhưng bạn gọi nó là' take (iterable, n) '. – bcat

1

Tôi muốn bắt đầu với

if limit is None: return 

vì không có gì có thể xảy ra với limit khi nó bắt đầu là None (nếu không có tác dụng phụ mong muốn trong lặp lại và trong tính toán của predicate - nếu có, sau đó, trong trường hợp này bạn chỉ có thể làm for i in xrange(10**5): predicate(i)).

Nếu limit không phải là None, sau đó bạn chỉ muốn thực hiện max(limit, 1) tính toán của predicate đó là đúng sự thật, vì vậy một itertools.islice của một itertools.ifilter sẽ làm gì:

import itertools as it 

def ello_bruce(limit=None): 
    if limit is None: 
     for i in xrange(10**5): predicate(i) 
    else: 
     for _ in it.islice(
      it.ifilter(predicate, xrange(10**5), 
      max(limit, 1)): pass 
+0

xin lỗi, tôi đơn giản hóa quá nhiều, nó chỉ là tác dụng phụ của biến vị ngữ() mà tôi cần. Tôi cũng đã thử một 'giới hạn' như gợi ý nhưng cảm thấy tôi đã lặp lại mã trong các chi nhánh. – msw

0

gì bạn muốn làm dường như hoàn toàn phù hợp cho một while loop:

def ello_bruce(limit=None): 
    max = 10**5 
    # if you consider 0 to be an invalid value for limit you can also do 
    # if limit: 
    if limit is None: 
     limit = max 

    while max and limit: 
     if predicate(i): 
      limit -= 1 
     max -=1 

Vòng lặp dừng nếu max hoặc limit đạt 0.

1

Bạn nên loại bỏ các ifs lồng nhau:

if predicate(i) and not limit is None: 
    ... 
0

Um. Theo tôi hiểu, predicate chỉ tính toán trong phân khúc và bạn hoàn toàn bỏ qua giá trị trả lại của nó, phải không?

Đây là một mất:

import itertools 

def ello_bruce(limit=None): 
    if limit is None: 
     limiter= itertools.repeat(None) 
    else: 
     limiter= xrange(limit) 

    # since predicate is a Python function 
    # itertools looping won't be faster, so use plain for. 
    # remember to replace the xrange(100000) with your own iterator 
    for dummy in itertools.izip(xrange(100000), limiter): 
     pass 

Ngoài ra, loại bỏ các không cần thiết return True từ cuối predicate.

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