ProgramingTip

Python- 루프 내부의 이전 및 다음 값

bestdevel 2020. 11. 9. 20:27
반응형

Python- 루프 내부의 이전 및 다음 값


어디에서 어떻게 이런 일을 할 수 있습니까?

foo = somevalue
previous = next = 0

for (i=1; i<objects.length(); i++) {
    if (objects[i]==foo){
        previous = objects[i-1]
        next = objects[i+1]
    }
}

이것은 트릭을 할 것입니다.

foo = somevalue
previous = next_ = None
l = len(objects)
for index, obj in enumerate(objects):
    if obj == foo:
        if index > 0:
            previous = objects[index - 1]
        if index < (l - 1):
            next_ = objects[index + 1]

다음은 기능 에 대한 문서입니다 .enumerate


지금까지의 솔루션은 대부분 다루며 대부분은 복사하고 있습니다. 내 경험상 불가능한 일이 많다.

또한 유행하는 반복되는 요소를 반복합니다.

질문 제목은 " 루프 내부의 이전 및 다음 값 "이지만 루프 내부에서 대부분의 답변을 실행하면 각 요소에서 전체 목록을 다시 반복하여 검색하게됩니다.

그래서 방금 그 함수를 만들었습니다. 모듈을 사용하여 이터 러블을 분할 및 분할하고 이전 및 다음 요소와 함께 튜플을 생성합니다. 코드가하는 일이 정확히 무엇인지는 어떤 문제를 가지고 있는지 볼 수 있습니다.itertools

from itertools import tee, islice, chain, izip

def previous_and_next(some_iterable):
    prevs, items, nexts = tee(some_iterable, 3)
    prevs = chain([None], prevs)
    nexts = chain(islice(nexts, 1, None), [None])
    return izip(prevs, items, nexts)

그런 다음 루프에서 사용하면 이전 및 다음 항목이 있습니다.

mylist = ['banana', 'orange', 'apple', 'kiwi', 'tomato']

for previous, item, nxt in previous_and_next(mylist):
    print "Item is now", item, "next is", nxt, "previous is", previous

결과 :

Item is now banana next is orange previous is None
Item is now orange next is apple previous is banana
Item is now apple next is kiwi previous is orange
Item is now kiwi next is tomato previous is apple
Item is now tomato next is None previous is kiwi

모든 크기 목록 (파일, 세트 등)과 함께 작동합니다. 이렇게하면 시퀀스를 반복하고 루프 내에서 이전 및 다음 항목을 사용할 수 있습니다. 시퀀스에서 항목을 다시 검색 할 필요가 없습니다.

코드에 대한 간단한 설명 :

  • tee 입력 시퀀스에 3 개의 독립적 인 반복되는 것이 처음으로 사용됩니다.
  • chain두 시퀀스를 하나로 연결합니다. 여기에 단일 요소 시퀀스 [None]추가하는 데 사용 합니다.prevs
  • islice-th 요소를 첫 제외한 모든 요소의 시퀀스를 만드는 chain데 사용되며 None끝에 추가하는 데 사용됩니다.
  • 이제 some_iterable다음과 같은 3 개의 독립적 인 시퀀스가 ​​있습니다 .
    • prevs: None, A, B, C, D, E
    • items: A, B, C, D, E
    • nexts: B, C, D, E, None
  • 마지막으로 izip3 개의 시퀀스를 3 개의 시퀀스로 변경하는 데 사용됩니다.

참고 izip모든 입력 입력 순서가 소진 될때의 마지막 요소는, 중지 그래서 prevs마지막 요소가 될 것이라고 이러한 요소가 없습니다 - 올바른 무시됩니다 prev. 마지막 요소는 우리를 제거하려고 할 수 prevs있지만 izip의 동작은

또한 점에 유의 tee, izip, islicechain으로부터 on- itertools모듈; 즉석에서 (게으른) 입력 시퀀스에 대해 작동 방식으로 만들고 전체 시퀀스를 한 번에 메모리에 필요가 없습니다.

에서는 python 3가져 오는 동안 오류가-display 됩니다 . 대신 izip사용할 수 있습니다 . 수입 할 필요는 , 그것은 미리 정의되지 않는다 - 소스zipizipzippython 3


목록 이해력을 사용하여 현재, 이전 및 다음 요소가있는 3- 튜플을 반환합니다.

three_tuple = [(current, 
                my_list[idx - 1] if idx >= 1 else None, 
                my_list[idx + 1] if idx < len(my_list) - 1 else None) for idx, current in enumerate(my_list)]

기능> = 2.5 간결성을 위해 조건식 사용

def prenext(l,v) : 
   i=l.index(v)
   return l[i-1] if i>0 else None,l[i+1] if i<len(l)-1 else None


# example
x=range(10)
prenext(x,3)
>>> (2,4)
prenext(x,0)
>>> (None,2)
prenext(x,9)
>>> (8,None)

경계 오류가없는 생성기를 사용하는 버전은 다음과 같습니다.

def trios(input):
    input = iter(input) # make sure input is an iterator
    try:
        prev, current = input.next(), input.next()
    except StopIteration:
        return
    for next in input:
        yield prev, current, next
        prev, current = current, next

def find_prev_next(objects, foo):
    prev, next = 0, 0
    for temp_prev, current, temp_next in trios(objects):
        if current == foo:
            prev, next = temp_prev, temp_next
    return prev, next

print find_prev_next(range(10), 1)
print find_prev_next(range(10), 0)
print find_prev_next(range(10), 10)
print find_prev_next(range(0), 10)
print find_prev_next(range(1), 10)
print find_prev_next(range(2), 10)

경계 동작은 코드와 달리 첫 번째 또는 마지막 요소에서 "foo"를 찾지 않습니다. 다시 말하지만, 경계 의미론은 이상하며 코드에서하기 어렵습니다. :)


기능 만 사용하고 다른 내장으로 확장 할 수 있습니다.

values = [1, 2, 3, 4]
offsets = [None] + values[:-1], values, values[1:] + [None]
for value in list(zip(*offsets)):
    print(value) # (previous, current, next)

(None, 1, 2)
(1, 2, 3)
(2, 3, 4)
(3, 4, None)

요소를 순환하고 싶은이 문제에 대한 해결책을 찾는 사람 아래가 많은 일 수 있습니다.

from collections import deque  

foo = ['A', 'B', 'C', 'D']

def prev_and_next(input_list):
    CURRENT = input_list
    PREV = deque(input_list)
    PREV.rotate(-1)
    PREV = list(PREV)
    NEXT = deque(input_list)
    NEXT.rotate(1)
    NEXT = list(NEXT)
    return zip(PREV, CURRENT, NEXT)

for previous_, current_, next_ in prev_and_next(foo):
    print(previous_, current_, next)

index목록에서 사용 하여 위치를 somevalue다음 필요에 따라 이전 및 다음을 사용할 수 있습니다.


def find_prev_next(elem, elements):
    previous, next = None, None
    index = elements.index(elem)
    if index > 0:
        previous = elements[index -1]
    if index < (len(elements)-1):
        next = elements[index +1]
    return previous, next


foo = 'three'
list = ['one','two','three', 'four', 'five']

previous, next = find_prev_next(foo, list)

print previous # should print 'two'
print next # should print 'four'



AFAIK 이것은 꽤 빠르지 만 테스트하는 것입니다.

def iterate_prv_nxt(my_list):
    prv, cur, nxt = None, iter(my_list), iter(my_list)
    next(nxt, None)

    while True:
        try:
            if prv:
                yield next(prv), next(cur), next(nxt, None)
            else:
                yield None, next(cur), next(nxt, None)
                prv = iter(my_list)
        except StopIteration:
            break

사용 예 :

>>> my_list = ['a', 'b', 'c']
>>> for prv, cur, nxt in iterate_prv_nxt(my_list):
...    print prv, cur, nxt
... 
None a b
a b c
b c None

생성기를 사용하면 매우 간단합니다.

signal = ['→Signal value←']
def pniter( iter, signal=signal ):
    iA = iB = signal
    for iC in iter:
        if iB is signal:
            iB = iC
            continue
        else:
            yield iA, iB, iC
        iA = iB
        iB = iC
    iC = signal
    yield iA, iB, iC

if __name__ == '__main__':
    print('test 1:')
    for a, b, c in pniter( range( 10 )):
        print( a, b, c )
    print('\ntest 2:')
    for a, b, c in pniter([ 20, 30, 40, 50, 60, 70, 80 ]):
        print( a, b, c )
    print('\ntest 3:')
    cam = { 1: 30, 2: 40, 10: 9, -5: 36 }
    for a, b, c in pniter( cam ):
        print( a, b, c )
    for a, b, c in pniter( cam ):
        print( a, a if a is signal else cam[ a ], b, b if b is signal else cam[ b ], c, c if c is signal else cam[ c ])
    print('\ntest 4:')
    for a, b, c in pniter([ 20, 30, None, 50, 60, 70, 80 ]):
        print( a, b, c )
    print('\ntest 5:')
    for a, b, c in pniter([ 20, 30, None, 50, 60, 70, 80 ], ['sig']):
        print( a, b, c )
    print('\ntest 6:')
    for a, b, c in pniter([ 20, ['→Signal value←'], None, '→Signal value←', 60, 70, 80 ], signal ):
        print( a, b, c )

None을 포함하고 신호 값과 동일한 값을 포함하는 테스트는 여전히 작동합니다. 신호 값에 대한 검사는 "is"를 사용하고 신호는 Python이 인턴하지 않는 값이기 때문입니다. 그러나 모든 싱글 톤 마커 값을 신호로 사용할 수 있으므로 일부 상황에서 사용자 코드를 단순화 할 수 있습니다.


Pythonic하고 우아한 방법 :

objects = [1, 2, 3, 4, 5]
value = 3
if value in objects:
   index = objects.index(value)
   previous_value = objects[index-1]
   next_value = objects[index+1] if index + 1 < len(objects) else None

참고 URL : https://stackoverflow.com/questions/1011938/python-previous-and-next-values-inside-a-loop

반응형