表达条件有界循环的更pythonic方式?

时间:2022-03-11 22:37:59

I've got a loop that wants to execute to exhaustion or until some user specified limit is reached. I've got a construct that looks bad yet I can't seem to find a more elegant way to express it; is there one?

我有一个循环,想要执行到耗尽或直到达到一些用户指定的限制。我有一个看起来不好的结构,但我似乎找不到更优雅的表达方式;有吗?

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

Holy nesting! There has to be a better way. For purposes of a working example, xrange is used where I normally have an iterator of finite but unknown length (and predicate sometimes returns False).

神圣的筑巢!一定有更好的方法。出于工作示例的目的,使用xrange,其中我通常具有有限但未知长度的迭代器(并且谓词有时返回False)。

6 个解决方案

#1


11  

Maybe something like this would be a little better:

也许这样的事情会好一点:

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

#2


2  

I'd take a good look at the itertools library. Using that, I think you'd have something like...

我会好好看一下itertools库。使用它,我想你会有......

# 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)

#3


1  

I'd start with

我先说

if limit is None: return

since nothing can ever happen to limit when it starts as None (if there are no desirable side effects in the iteration and in the computation of predicate -- if there are, then, in this case you can just do for i in xrange(10**5): predicate(i)).

因为没有任何事情可以发生限制,当它开始为无(如果在迭代和谓词的计算中没有理想的副作用 - 如果有,那么,在这种情况下,你可以在xrange中为我做(10) ** 5):谓词(i))。

If limit is not None, then you just want to perform max(limit, 1) computations of predicate that are true, so an itertools.islice of an itertools.ifilter would do:

如果limit不是None,那么你只想执行谓词的max(limit,1)计算是真的,所以itertools.isilice的itertools.islice会这样做:

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

#4


1  

You should remove the nested ifs:

您应该删除嵌套的ifs:

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

#5


0  

What you want to do seems perfectly suited for a while loop:

你想做什么似乎非常适合while循环:

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

The loop stops if either max or limit reaches zero.

如果max或limit达到零,则循环停止。

#6


0  

Um. As far as I understand it, predicate just computes in segments, and you totally ignore its return value, right?

嗯。据我所知,谓词只是按段计算,你完全忽略它的返回值,对吧?

This is another take:

这是另一种看法:

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

Also, remove the unneeded return True from the end of predicate.

另外,从谓词末尾删除不需要的返回True。

#1


11  

Maybe something like this would be a little better:

也许这样的事情会好一点:

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

#2


2  

I'd take a good look at the itertools library. Using that, I think you'd have something like...

我会好好看一下itertools库。使用它,我想你会有......

# 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)

#3


1  

I'd start with

我先说

if limit is None: return

since nothing can ever happen to limit when it starts as None (if there are no desirable side effects in the iteration and in the computation of predicate -- if there are, then, in this case you can just do for i in xrange(10**5): predicate(i)).

因为没有任何事情可以发生限制,当它开始为无(如果在迭代和谓词的计算中没有理想的副作用 - 如果有,那么,在这种情况下,你可以在xrange中为我做(10) ** 5):谓词(i))。

If limit is not None, then you just want to perform max(limit, 1) computations of predicate that are true, so an itertools.islice of an itertools.ifilter would do:

如果limit不是None,那么你只想执行谓词的max(limit,1)计算是真的,所以itertools.isilice的itertools.islice会这样做:

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

#4


1  

You should remove the nested ifs:

您应该删除嵌套的ifs:

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

#5


0  

What you want to do seems perfectly suited for a while loop:

你想做什么似乎非常适合while循环:

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

The loop stops if either max or limit reaches zero.

如果max或limit达到零,则循环停止。

#6


0  

Um. As far as I understand it, predicate just computes in segments, and you totally ignore its return value, right?

嗯。据我所知,谓词只是按段计算,你完全忽略它的返回值,对吧?

This is another take:

这是另一种看法:

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

Also, remove the unneeded return True from the end of predicate.

另外,从谓词末尾删除不需要的返回True。