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]
    }
}
8 ответов:
Это должно сделать трюк.
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модуль, разбивает и разрезает iterable, и генерирует кортежи с предыдущими и следующими элементами вместе. Не совсем то, что делает ваш код, но стоит взглянуть, потому что он, вероятно, может решить вашу проблему.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используется для добавления aNoneдо конца- теперь есть 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-кортеж с текущими, предыдущими и следующими элементами:
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)
вы могли бы просто использовать
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