2010-04-26 4 views
5

피곤하거나 특정 사용자 한도에 도달 할 때까지 실행하려는 루프가 있습니다. 나는보기에는 좋지 않은 구조를 가지고 있지만 그것을 표현하는보다 우아한 방법을 찾을 수는 없다. 거기있어?조건부로 묶인 루프를 표현하는 좀 더 파이썬 적 방법?

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 

거룩한 중첩! 더 좋은 방법이 있어야합니다. 작업 예제의 경우, 일반적으로 유한하지만 알 수없는 길이의 반복자가 있고 (때로는 술어가 False를 반환하는) xrange이 사용됩니다.

+0

최소한 루프 앞에 한계가 없음이 있는지 확인하고 조건이 참일 때마다 확인하지 않고 리턴하십시오. 그렇다고해서 훨씬 더 파이썬적일 수는 없지만 루프에서 불필요한 계산을 많이 줄일 수 있습니다. –

+0

그는 실제 행동을 여기에 놓는 것을 잊어 버렸지 만, 나는 limit = None이 "무언가를하지 말라"가 아니라 "무제한"을 의미한다고 생각합니다. –

+0

여기에서 만들 수있는 가장 간단한 정리는 'if not predicate (i) : continue' 조건을 뒤집어서 여분의 중첩 레벨에 블록의 전체 나머지를 두는 것을 피하는 것입니다. 이것은 많은 코드에 적용되므로 일반적으로 배우는 것이 좋습니다. –

답변

11

어쩌면 이런 일이 조금 더 나은 것 :

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 좋은 해결책! –

+0

완벽한, 감사합니다. – msw

+6

이렇게하면 너무 많은 부분이 한 줄로 압축됩니다. 원래 코드가 더 명확합니다. 둥지를 쪼개는 것이 많은 도움이 될 것입니다. 'iter = ifilter (술어, xrange (10 ** 5))'그리고 islice (iter, limit)'에 대해. –

2

나는 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) 
+0

+1 실제로 모듈에는 미묘한 힘 (또는 강력한 미묘함)이 있습니다. – msw

+0

'take '매개 변수가 반대로되어 있다고 생각합니다. 즉,'def take (n, iterable)'을 가지고 있지만'take (iterable, n)'처럼 호출합니다. – bcat

1

내가

if limit is None: return 

으로 시작 했죠 None으로 시작하면 limit으로 아무 일도 일어나지 않을 수 있기 때문에 (반복 및 바람직한 계산에 predicate의 부작용이 없다면, 이 경우에는 for i in xrange(10**5): predicate(i)) 할 수 있습니다. 당신이 원하는 것은 매우 적합 보인다

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

미안하지만, 나는 너무 많이 단순화했다, 내가 필요로하는 술어()의 부작용 일 뿐이다. 또한 제안대로'if limit'을 시도했지만 브랜치에서 코드를 반복하고 있다고 느꼈습니다. – msw

0

: limit 만약

는 그냥 그래서 itertools.ifilteritertools.islice 할 것, 해당 predicatemax(limit, 1) 계산을 수행하려면, None 아니다 while 루프 : 하나 또는 maxlimit가 0에 도달하는 경우

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 

루프는 정지한다.

1

당신은 중첩 된 IFS를 제거해야합니다 :

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

음. 내가 이해하는 한, predicate은 세그먼트 단위로 계산되며 반환 값은 완전히 무시합니다. 맞습니까?

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 

또한, 제거 불필요한 return Truepredicate의 끝에서 :

다른 걸릴 수 있습니다.

관련 문제