How to access previous/next element while for looping?

Is there a way to access a list(or tuple, or other iterable)'s next, or previous element while looping through with for loop?

l=[1,2,3]
for item in l:
    if item==2:
        get_previous(l,item)

Answers


Expressed as a generator function:

def neighborhood(iterable):
    iterator = iter(iterable)
    prev_item = None
    current_item = next(iterator)  # throws StopIteration if empty.
    for next_item in iterator:
        yield (prev_item, current_item, next_item)
        prev_item = current_item
        current_item = next_item
    yield (prev_item, current_item, None)

Usage:

for prev,item,next in neighborhood(l):
    print prev, item, next

One simple way.

l=[1,2,3]
for i,j in zip(l, l[1:]):
    print i, j

l=[1,2,3]
for i,item in enumerate(l):
    if item==2:
        get_previous=l[i-1]
        print get_previous

>>>1

When dealing with generators where you need some context, I often use the below utility function to give a sliding window view on an iterator:

import collections, itertools

def window(it, winsize, step=1):
    """Sliding window iterator."""
    it=iter(it)  # Ensure we have an iterator
    l=collections.deque(itertools.islice(it, winsize))
    while 1:  # Continue till StopIteration gets raised.
        yield tuple(l)
        for i in range(step):
            l.append(it.next())
            l.popleft()

It'll generate a view of the sequence N items at a time, shifting step places over. eg.

>>> list(window([1,2,3,4,5],3))
[(1, 2, 3), (2, 3, 4), (3, 4, 5)]

When using in lookahead/behind situations where you also need to deal with numbers without having a next or previous value, you may want pad the sequence with an appropriate value such as None.

l= range(10)
# Print adjacent numbers
for cur, next in window(l + [None] ,2):
    if next is None: print "%d is the last number." % cur
    else: print "%d is followed by %d" % (cur,next)

I know this is old, but why not just use enumerate?

l = ['adam', 'rick', 'morty', 'adam', 'billy', 'bob', 'wally', 'bob', 'jerry']

for i, item in enumerate(l):
    if i == 0:
        previous_item = None
    else:
        previous_item = l[i - 1]

    if i == len(l) - 1:
        next_item = None
    else:
        next_item = l[i + 1]

    print('Previous Item:', previous_item)
    print('Item:', item)
    print('Next Item:', next_item)
    print('')

    pass

If you run this you will see that it grabs previous and next items and doesn't care about repeating items in the list.


Check out the looper utility from the Tempita project. It gives you a wrapper object around the loop item that provides properties such as previous, next, first, last etc.

Take a look at the source code for the looper class, it is quite simple. There are other such loop helpers out there, but I cannot remember any others right now.

Example:

> easy_install Tempita
> python
>>> from tempita import looper
>>> for loop, i in looper([1, 2, 3]):
...     print loop.previous, loop.item, loop.index, loop.next, loop.first, loop.last, loop.length, loop.odd, loop.even
... 
None 1 0 2 True False 3 True 0
1 2 1 3 False False 3 False 1
2 3 2 None False True 3 True 0

I don't think there is a straightforward way, especially that an iterable can be a generator (no going back). There's a decent workaround, relying on explicitly passing the index into the loop body:

for itemIndex, item in enumerate(l):
    if itemIndex>0:
        previousItem = l[itemIndex-1]
    else:
        previousItem = None 

The enumerate() function is a builtin.


Iterators only have the next() method so you cannot look forwards or backwards, you can only get the next item.

enumerate(iterable) can be useful if you are iterating a list or tuple.


Immediately previous?

You mean the following, right?

previous = None
for item in someList:
    if item == target: break
    previous = item
# previous is the item before the target

If you want n previous items, you can do this with a kind of circular queue of size n.

queue = []
for item in someList:
    if item == target: break
    queue .append( item )
    if len(queue ) > n: queue .pop(0)
if len(queue ) < n: previous = None
previous = previous[0]
# previous is *n* before the target

If you want the solution to work on iterables, the itertools' docs has a recipe that does exactly what you want:

import itertools

def pairwise(iterable):
    "s -> (s0,s1), (s1,s2), (s2, s3), ..."
    a, b = itertools.tee(iterable)
    next(b, None)
    return zip(a, b)

If you're using Python 2.x, use itertools.izip instead of zip


Not very pythonic, but gets it done and is simple:

l=[1,2,3]
for index in range(len(l)):
    if l[index]==2:
        l[index-1]

TO DO: protect the edges


The most simple way is to search the list for the item:

def get_previous(l, item):
    idx = l.find(item)
    return None if idx == 0 else l[idx-1]

Of course, this only works if the list only contains unique items. The other solution is:

for idx in range(len(l)):
    item = l[idx]
    if item == 2:
        l[idx-1]

Need Your Help

Writing lambda expressions in common lisp

common-lisp lambda clisp

I am currently reading ANSI Common Lisp by Paul Graham, and I have a question about writing lambda expressions.

How can I add a device to development portal in Xcode 6?

ios code-signing xcode6 provisioning-profile

I see that Xcode6 has removed the "Devices" tab from the organizer and moved it to a separate "Devices" tab in Window > Devices.