Как я могу сделать такую вещь в 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]
}
}
Как я могу сделать такую вещь в 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
используется для создания последовательности всех элементов, кроме первого, затем 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
- исходный код
Используя понимание списка, верните 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)]
Здесь версия с использованием генераторов без граничных ошибок:
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" в первом или последнем элементе, в отличие от вашего кода. Опять же, граница семантики странная... и трудно понять из вашего кода:)
с использованием условных выражений для краткости для 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)
Вы можете просто использовать 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 не интернирует. Однако в качестве сигнала можно использовать любое значение одноэлементного маркера, что в некоторых случаях может упростить код пользователя.
Я не знаю, как это еще не произошло, поскольку он использует только встроенные функции и легко расширяется на другие смещения:
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)
Питонический и элегантный способ:
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