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] } } 

这应该做的伎俩。

 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函数的文档。

目前解决scheme只处理列表,而大部分都是复制列表。 根据我的经验,很多时候这是不可能的。

此外,他们不处理的事实,你可以在列表中重复的元素。

你的问题的标题是“ 循环内的上一个和下一个值 ”,但是如果你在循环内部运行大部分答案,那么你将最终在每个元素上遍历整个列表来find它。

所以我刚刚创build了一个函数。 使用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 

它可以处理任何大小的列表(因为它不会复制列表)以及任何可迭代(文件,集合等)。 通过这种方式,您可以迭代序列,并在循环中使用前一个和下一个项目。 无需再次search序列中的项目。

代码的简短说明:

  • tee用于在input序列上有效地创build3个独立的迭代器
  • 将两个序列链接成一个; 它在这里被用来追加一个单元素序列[None]prevs
  • islice被用来创build除了第一个元素之外的所有元素的序列,然后chain被用来在它的末尾附加一个None
  • 现在有3个基于some_iterable独立序列,看起来像:
    • prevsNone, A, B, C, D, E
    • itemsA, B, C, D, E
    • nextsB, C, D, E, None
  • 最后izip被用来将3个序列变成一个三元组序列。

请注意,当任何input序列耗尽时, izip停止,所以izip的最后一个元素将被忽略,这是正确的 – 没有这样的元素,最后一个元素将成为它的prev 。 我们可以尝试去除izip的最后一个元素,但是izip的行为使得这种冗余

另请注意, teeizipislicechain来自itertools模块; 它们在运行中(懒惰地)操作它们的input序列,这使得它们有效,并且不需要在任何时候一次将全部序列存储在存储器中。

这是一个使用没有边界错误的发生器的版本:

 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”的第一个或最后一个元素。 再一次,边界语义是奇怪的…而且很难从你的代码中找出:)

使用列表理解,返回一个包含当前元素,前一元素和下一个元素的三元组:

 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)] 

使用条件expression式来简化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来findsomevalue位置,然后根据需要获取previous和next:

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'
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这应该是相当快,但我没有testing它:

 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 ab abc bc None 

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