1

Say I want to iterate through a list. Each time I iterate I want to compute something using both the current and next terms. I could do something like

mylist = [1, 2, 3, 4]
for i in range(len(mylist)):
    try:
        compute(mylist[i], mylist[i+1])
    except IndexError:
        compute(mylist[i])

I could also do

mylist = [1, 2, 3, 4]
for num in mylist:
    try:
        compute(num, mylist[mylist.index(num)+1])
    except IndexError:
        compute(num)

Neither of these seems particularly good. Is there a more pythonic approach to doing this?

Karl Knechtel
  • 62,466
  • 11
  • 102
  • 153
Bruno
  • 55
  • 6

4 Answers4

1

You can use built-in function enumerate:

mylist = [1, 2, 3, 4]
for i, num in enumerate(mylist):
    try:
        compute(num, mylist[i+1])
    except IndexError:
        compute(num)

But choosing between your two implementations is rather easy - second is not only far slower (O(n^2)), but also has weird semantics for repeating elements.

zch
  • 14,931
  • 2
  • 41
  • 49
1

There are three ways to do that (although I would probably prefer first one, unless your conditions are different):

  1. Use itertools.izip() - it will be efficient and Pythonic:

    for item1, item2 in itertools.izip(my_list, my_list[1:]):
        # do something...
    
  2. Use enumerate():

    for index, item in enumerate(my_list):
        # do something...
    
  3. Store previous row in a variable (the example assumes there is no None in your list):

    previous = None
    for item in my_list:
        if previous is None:
            previous = item
            continue
        # do something...
    
Tadeck
  • 132,510
  • 28
  • 152
  • 198
0

A functional style that doesn't use itertools might look something like:

for t in zip(mylist, mylist[1:]):
    compute(*t)

If performance is tantamount you can prevent the creation of the intermeida list during zip by using itertools.izip.

To cover the special case as shown in the question, use:

for t in zip(mylist, mylist[1:]) + [(mylist[-1],)]
    compute(*t)
cmh
  • 10,612
  • 5
  • 30
  • 40
  • Why is this inefficient? – Bruno Nov 27 '12 at 00:33
  • It isn't actually that bad, but zip creates an intermediate list that is unnecessary. Using [itertools.izip](http://docs.python.org/2/library/itertools.html#itertools.izip), is preferable. – cmh Nov 27 '12 at 00:37
0

To cover your special case at the end, you need:

for t in zip(mylist, mylist[1:]) + [(mylist[-1],)]
    compute(*t)
Eric
  • 95,302
  • 53
  • 242
  • 374