이전, 현재 및 다음 항목에 액세스하여 객체 목록을 반복하려면 어떻게해야합니까? 파이썬에서이 C / C ++ 코드처럼?
foo = somevalue;
previous = next = 0;
for (i=1; i<objects.length(); i++) {
if (objects[i]==foo) {
previous = objects[i-1];
next = objects[i+1];
}
}
이전, 현재 및 다음 항목에 액세스하여 객체 목록을 반복하려면 어떻게해야합니까? 파이썬에서이 C / C ++ 코드처럼?
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
목록에서 정확히 한 번 발생하는 것이 보장 됩니까? 곱셈이 발생하면 여기에서 일부 접근 방식이 실패하거나 첫 번째 접근 방식 만 찾습니다. 그리고 이것이 발생하지 않으면 다른 접근 방식이 실패하거나 ValueError와 같은 예외가 발생합니다. 몇 가지 테스트 케이스를 제공하면 도움이 될 것입니다.
답변:
이것은 트릭을 할 것입니다.
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
기능 에 대한 문서입니다 .
obj
및 next_
의도하지 않은 부작용이있을 수 있습니다 마지막 반복에 대한 동일한 개체가 될 것입니다.
index
에서 실행되지해야 1 ... (l-1)
하지, 0 ... l
당신이 여기 가지고, 그리고 필요하면-절을 특수 맡았다. Btw, 매개 변수가 enumerate(..., start=1)
있지만 end
. 그래서 우리는 실제로 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
첫 번째 요소를 제외한 모든 요소의 시퀀스를 만드는 chain
데 사용되며 None
끝에 a 를 추가하는 데 사용됩니다.some_iterable
다음과 같은 3 개의 독립적 인 시퀀스가 있습니다 .
prevs
: None, A, B, C, D, E
items
: A, B, C, D, E
nexts
: B, C, D, E, None
izip
3 개의 시퀀스를 3 개의 시퀀스로 변경하는 데 사용됩니다.참고 izip
모든 입력 순서가 소진 될때의 마지막 요소는, 그래서 중지 prevs
마지막 요소가 될 것이라고 이러한 요소가 없습니다 - 올바른 무시됩니다 prev
. 우리는 마지막 요소를 제거하려고 할 수 prevs
있지만 izip
의 동작은
또한 점에 유의 tee
, izip
, islice
와 chain
으로부터 온 itertools
모듈; 즉석에서 (게으른) 입력 시퀀스에 대해 작동하므로 효율적으로 만들고 전체 시퀀스를 한 번에 메모리에 저장할 필요가 없습니다.
에서는 python 3
가져 오는 동안 오류가 표시 됩니다 . 대신 izip
사용할 수 있습니다 . 수입 할 필요는 , 그것은에 미리 정의되지 않는다 - 소스zip
izip
zip
python 3
izip
에서 내장 zip
함수 로 대체 될 수 있다는 것을 언급 할 가치가있을 것입니다 ;-)
다음은 경계 오류없이 생성기를 사용하는 버전입니다.
def trios(iterable):
it = iter(iterable)
try:
prev, current = next(it), next(it)
except StopIteration:
return
for next in it:
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"를 찾지 않는다는 것입니다. 다시 말하지만, 경계 의미론은 이상하며 코드에서 파악하기 어렵습니다. :)
요소를 순환하고 싶은이 문제에 대한 해결책을 찾는 사람에게는 아래가 효과적 일 수 있습니다.
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)
objects[i-1], objects[i], objects[i+1]
됩니까? 아니면 발전기? 그것은 나에게 완전히 모호한 것처럼 보입니다. 또한 PREV와 NEXT가 데이터를 복사하기 때문에 3x 메모리를 불필요하게 사용합니다.
i+1
목록의 마지막 요소에 대한 접근 방식을 어떻게 얻 습니까? 다음 요소는 첫 번째 요소 여야합니다. 나는 경계를 벗어난다.
생성기를 사용하면 매우 간단합니다.
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이 인턴하지 않는 값이기 때문입니다. 그러나 모든 싱글 톤 마커 값을 신호로 사용할 수 있으므로 일부 상황에서 사용자 코드를 단순화 할 수 있습니다.
if iB is signal
signal = None이 아니라면 객체를 비교 하는 데 절대 사용하지 마십시오 None
. iter
builtin을 숨기므로 인수 이름으로 사용하지 마십시오 iter()
. 동일합니다 next
. 어쨌든 발전기 접근 방식은 간단 할 수 있습니다yield prev, curr, next_
is
대신 ==
당신이 문자열을 인턴으로 CPython에 의존하고 있기 때문에, 문자열을 함께 멀리 얻을 수 있지만, 그렇다하더라도 왜, 그것은 잘 알려진 함정이야, 여기에 여러 이유가 있습니다 v1 = 'monkey'; v2 = 'mon'; v3 = 'key
, 다음 v1 is (v2 + v3)
제공 False
. 코드가 정수 / 문자열 대신 객체를 사용하도록 전환하면 사용 is
이 중단됩니다. 따라서 일반적으로 ==
평등을 비교 하는 데 사용해야 합니다.
두 가지 간단한 솔루션 :
alist = ['Zero', 'One', 'Two', 'Three', 'Four', 'Five']
prev = alist[0]
curr = alist[1]
for nxt in alist[2:]:
print(f'prev: {prev}, curr: {curr}, next: {nxt}')
prev = curr
curr = nxt
Output[1]:
prev: Zero, curr: One, next: Two
prev: One, curr: Two, next: Three
prev: Two, curr: Three, next: Four
prev: Three, curr: Four, next: Five
alist = ['Zero', 'One', 'Two', 'Three', 'Four', 'Five']
prev = None
curr = alist[0]
for nxt in alist[1:] + [None]:
print(f'prev: {prev}, curr: {curr}, next: {nxt}')
prev = curr
curr = nxt
Output[2]:
prev: None, curr: Zero, next: One
prev: Zero, curr: One, next: Two
prev: One, curr: Two, next: Three
prev: Two, curr: Three, next: Four
prev: Three, curr: Four, next: Five
prev: Four, curr: Five, next: None
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
나는 이것이 효과가 있고 복잡하지 않다고 생각한다.
array= [1,5,6,6,3,2]
for i in range(0,len(array)):
Current = array[i]
Next = array[i+1]
Prev = array[i-1]
매우 C / C ++ 스타일 솔루션 :
foo = 5
objectsList = [3, 6, 5, 9, 10]
prev = nex = 0
currentIndex = 0
indexHigher = len(objectsList)-1 #control the higher limit of list
found = False
prevFound = False
nexFound = False
#main logic:
for currentValue in objectsList: #getting each value of list
if currentValue == foo:
found = True
if currentIndex > 0: #check if target value is in the first position
prevFound = True
prev = objectsList[currentIndex-1]
if currentIndex < indexHigher: #check if target value is in the last position
nexFound = True
nex = objectsList[currentIndex+1]
break #I am considering that target value only exist 1 time in the list
currentIndex+=1
if found:
print("Value %s found" % foo)
if prevFound:
print("Previous Value: ", prev)
else:
print("Previous Value: Target value is in the first position of list.")
if nexFound:
print("Next Value: ", nex)
else:
print("Next Value: Target value is in the last position of list.")
else:
print("Target value does not exist in the list.")
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
value
끝에 있으면 실패합니다 . 또한, 같은 마지막 요소를 반환 previous_value
하는 경우 value
첫 번째입니다.
previous_value
목록에서 마지막 요소를 반환하고 next_value
올릴 것이다 IndexError
그리고 그게 오류
value
더에 한 번 이상 발생할 수 objects
있지만, 사용 .index()
(이 발생하지 않는 경우 또는 ValueError를)에만 첫 번째 항목을 찾을 수 있습니다.