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