2010-04-26 11 views
5

Yorgunluğa veya istenen kullanıcı limitine ulaşılana kadar yürütmek isteyen bir döngü var. Kötü görünen bir yapım var ama bunu ifade etmenin daha zarif bir yolunu bulamıyorum; orada var mıKoşullu olarak sınırlanmış döngüyü ifade etmek için daha pythonik bir yol?

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 

Kutsal yuvalama! Daha iyi bir yolu olmalı. Bir çalışma örneğinin amaçları için, xrange, normalde sonlu ancak bilinmeyen uzunluktaki yineleyiciye sahip olduğum (ve bazen yüklemeyi yanlış olarak döndüren) olarak kullanılır.

+0

En azından sınırın Döngüden Önce Olup Olmadığını kontrol edebilir ve eğer doğruysa, herhangi bir zamanda doğruyu kontrol etmek yerine geri dönebilirsiniz. Bu gerçekten daha fazla pythonik yapmaz, ancak döngüde çok fazla gereksiz hesaplamalar kaydedebilir. –

+0

Gerçek eylemi buraya koymayı unuttu, fakat limit bekliyorum = Yok "sınır yok" anlamına geliyor, "bir şey yapma" değil. –

+0

Burada yapabileceğiniz en basit temizlemenin, durumu tersine çevirdiğini unutmayın: 'eğer (i): devam etmiyorsanız, bloğun kalan kısmını ek bir yuvalama seviyesine yerleştirmekten kaçınılır. Bu çok fazla kod için geçerlidir, bu yüzden genel olarak öğrenmek iyi bir şeydir. –

cevap

11

Belki böyle bir şey biraz daha iyi olurdu:

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 Güzel çözüm! –

+0

mükemmel, teşekkürler. – msw

+6

Bu, bir satıra çok fazla yol veriyor; Orijinal kod daha açık. Yuvalamayı ayırmak için çok yardımcı olacaktır; iter = ifilter (yüklem, xrange (10 ** 5)) 've sonra da i 'inde (iter, limit)' için. –

2

itertools kitaplığına iyi bakarım. Bu kullanarak, ... gibi bir şey olurdu düşünmek

# 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 gerçekten, bu modülün bazı ince güçleri (veya güçlü incelikleri) vardır. – msw

+0

'Take' parametrelerinin tersine döndüğünü düşünüyorum, yani 'def' (n, iterable) 'karakterine sahipsin, ama sen buna 'al' (iterable, n)' diyorsun. – bcat

1

Ben

if limit is None: return 

başlardım(predicate hesaplamasında istenen yan etkiler olmadığında - limit hiçbir şey olmayacağından Bu durumda sadece for i in xrange(10**5): predicate(i) yapabilirsiniz. Ne yapmak istediğiniz bir derece uygun görünüyor

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

Üzgünüm, çok fazla basitleştirdim, sadece ihtiyacım olan yüklemin() yan etkileri. Ben de önerildiği gibi bir 'limit' denedim ama dallarda kodları tekrarladığımı hissettim. – msw

0

: limit Eğer

o zaman sadece bu yüzden bir itertools.ifilter bir itertools.islice yapardınız doğruysa predicate ait max(limit, 1) hesaplamaları gerçekleştirmek istediğiniz, None değil döngüsü sırasında: ya max veya limit sıfıra ulaştığında

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 

döngü durur.

1

Sen iç içe IFS kaldırması gerekir:

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

Um. Anladığım kadarıyla, predicate sadece bölümler halinde hesaplanıyor ve dönüş değerini tamamen yoksundur, değil mi?

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 

Ayrıca kaldırmak gereksiz return Truepredicate sonundan:

Bu

başka almaktır.

İlgili konular