Accessing next/prev element while for looping

Steven D'Aprano steve at REMOVETHIScyber.com.au
Sun Dec 18 07:36:29 EST 2005


On Sun, 18 Dec 2005 04:23:21 -0700, Joseph Garvin wrote:

> When I first came to Python I did a lot of C style loops like this:
> 
> for i in range(len(myarray)):
>     print myarray[i]
> 
> Obviously the more pythonic way is:
> 
> for i in my array:
>     print i
> 
> The python way is much more succinct. But a lot of times I'll be looping 
> through something, and if a certain condition is met, need to access the 
> previous or the next element in the array before continuing iterating.

If you need to do that, then either you need to rethink your algorithm so
that you only need to access one element at a time, or you can to change
your loop so that you aren't accessing one element at a time.

For example, you might grab elements three at a time, and if the middle
one meets a certain condition process them, and if not, do nothing.

There is no shortage of ways to handle your situation. However, I can't
help but feel that you probably need to rethink what you are trying to do.
I can't speak for others, but I've never come upon a situation where I
needed to access the element before and the element after the current one.

[thinks...] Wait, no, there was once, when I was writing a parser that
iterated over lines. I needed line continuations, so if the line ended
with a backslash, I needed to access the next line (and potentially the
line after that, and so forth indefinitely). I dealt with that by keeping
a cache of lines seen, adding to the cache if the line ended with a
backslash.

> I 
> don't see any elegant way to do this other than to switch back to the C 
> style loop and refer to myarray[i-1] and myarray[i+1], which seems 
> incredibly silly given that python lists under the hood are linked 
> lists, presumably having previous/next pointers although I haven't 
> looked at the interpeter source.

Python lists aren't linked lists? They are arrays.


> I could also enumerate:
> 
> for i, j in enumerate(myarray):
>     print myarray[i], j # Prints each element twice

j is a built-in object used to make complex numbers. Or at least it
was, until you rebound it to the current element from myarray. That's bad
practice, but since using complex numbers is rather unusual, one you will
probably get away with.


> And this way I can keep referring to j instead of myarray[i], but I'm 
> still forced to use myarray[i-1] and myarray[i+1] to refer to the 
> previous and next elements. Being able to do j.prev, j.next seems more 
> intuitive.

But that can't work, because j has no knowledge of the list it is part of:

myarray = ["spam", "parrot", "Spanish Inquisition"]
when i = 1, j = "parrot"

Since j is a string, it has no prev or next methods. How could "parrot"
possibly know that "spam" was the previous element?

You can't even have prev and next methods of the list myarray, because it
has no concept of the current element. The current element i is known by
the iterator used by the for loop, not the list it is iterating over.

You could possibly sub-class list, turning it into an iterator-like object
with next and prev methods, but be aware that "next" method has special
meaning to iterators.

You can probably create a generator or iterator that will do what you
want, but I suspect it won't be exactly straightforward. 


-- 
Steven.




More information about the Python-list mailing list