tags:

views:

820

answers:

9

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)
A: 

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.

chirag
A: 

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]
Aaron Digulla
A: 

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.

Rafał Dowgird
+12  A: 

Expressed as a generator function:

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

Usage:

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

Edit: I thought it would reduce the readability, but this way seem to look better.

MizardX
I might do "prev, item = item, next" in this case.
Paul Fisher
To make this cycle infinitely (no StopIteration), do `from itertools import cycle` and change the second line to: `iterator = cycle(iterable)`
Dennis Williamson
+3  A: 

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)
Brian
+1  A: 

you can iterate through a list 3 at a time, or in n-tuples:

http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/303279

http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/303060

Gene T
These will not create the desired effect of sliding window, which is what the original poster asked for
bgbg
A: 

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
S.Lott
+1  A: 
l=[1,2,3]
for i,item in enumerate(l):
    if item==2:
        get_previous=l[i-1]
        print get_previous

>>>1
Rudiger Wolf
+1  A: 

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
codeape