Подтвердить что ты не робот

Python - Предыдущие и следующие значения внутри цикла

Как я могу сделать такую ​​вещь в 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]
    }
}
4b9b3361

Ответ 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.

Ответ 2

Решения до сих пор имеют дело только со списками, и большинство копирует список. По моему опыту, много раз это было невозможно.

Кроме того, они не связаны с тем, что вы можете иметь повторяющиеся элементы в списке.

Название вашего вопроса гласит "Предыдущие и следующие значения внутри цикла", но если вы выполните большинство ответов здесь внутри цикла, вы в конечном итоге снова итерируете весь список для каждого элемента, чтобы найти его.

Так что я только что создал функцию, которая. используя модуль 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 к концу
  • Теперь есть 3 независимых последовательности, основанные на 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

Используя понимание списка, верните 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)]

Ответ 4

Здесь версия с использованием генераторов без граничных ошибок:

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" в первом или последнем элементе, в отличие от вашего кода. Опять же, граница семантики странная... и трудно понять из вашего кода:)

Ответ 5

с использованием условных выражений для краткости для 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)

Ответ 6

Для тех, кто ищет решение этой проблемы с циклическим изменением элементов, может сработать следующее:

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)

Ответ 7

Вы можете просто использовать 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'


Ответ 8

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

Ответ 9

Используя генераторы, это довольно просто:

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 не интернирует. Однако в качестве сигнала можно использовать любое значение одноэлементного маркера, что в некоторых случаях может упростить код пользователя.

Ответ 10

Я не знаю, как это еще не произошло, поскольку он использует только встроенные функции и легко расширяется на другие смещения:

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)

Ответ 11

Питонический и элегантный способ:

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