Как я могу перебирать список объектов, получая доступ к предыдущему, текущему и следующему элементам? Как этот код C / C ++ на 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
произойдет ровно один раз в списке? Если это происходит многократно, некоторые подходы здесь не сработают или найдут только первый. И если этого никогда не произойдет, другие подходы потерпят неудачу или вызовут исключения, такие как 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
а не как здесь, и нет необходимости в специальных if-предложениях. Кстати, есть параметр,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
в конецsome_iterable
которые выглядят так:prevs
:None, A, B, C, D, E
items
:A, B, C, D, E
nexts
:B, C, D, E, None
izip
используется для преобразования 3 последовательностей в одну последовательность триплетов.Обратите внимание, что
izip
останавливается, когда любая входная последовательность исчерпана, поэтому последний элементprevs
будет проигнорирован, что правильно - нет такого элемента, который был бы последним элементомprev
. Мы могли бы попытаться удалить последние элементы из,prevs
ноizip
поведение делает это избыточнымТакже отметим , что
tee
,izip
,islice
иchain
исходить отitertools
модуля; они оперируют своими входными последовательностями на лету (лениво), что делает их эффективными и не требует одновременного хранения всей последовательности в памяти в любое время.В
python 3
, он покажет ошибку при импортеizip
, вы можете использоватьzip
вместоizip
. Нет необходимости импортаzip
, он не предопределеныpython 3
- источникисточник
izip
можно заменить встроеннуюzip
функцию ;-)Используя понимание списка, верните 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)]
источник
Я не знаю, как это еще не произошло, поскольку он использует только встроенные функции и легко расширяется на другие смещения:
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)
источник
Вот версия с использованием генераторов без граничных ошибок:
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» в первом или последнем элементе, в отличие от вашего кода. Опять же, семантика границ странная ... и ее трудно понять из вашего кода :)
источник
использование условных выражений для краткости для python> = 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)
источник
Для тех, кто ищет решение этой проблемы, а также хочет циклически повторять элементы, ниже может сработать:
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]
? или генератор? Мне это кажется совершенно мракобесным. Кроме того, он без необходимости использует 3-кратную память, поскольку PREV и NEXT делают копии данных.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
в качестве имени аргумента, поскольку оно затеняет встроенный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.")
источник
Питонический и элегантный способ:
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, если этого не произойдет).