214

Using a for loop, how can I loop through all except the last item in a list? I would like to loop through a list checking each item against the one following it. Can I do this without using indices?

Karl Knechtel
  • 62,466
  • 11
  • 102
  • 153
David Sykes
  • 48,469
  • 17
  • 71
  • 80

6 Answers6

422
for x in y[:-1]

If y is a generator, then the above will not work.

slhck
  • 36,575
  • 28
  • 148
  • 201
freespace
  • 16,529
  • 4
  • 36
  • 58
  • 1
    That answers my question, thanks, but I forgot to ask how I would get the item after x. Is this possible? – David Sykes May 27 '09 at 09:19
  • I believe an "else" statement will allow you to handle what happens after the loop just don't forget to set x to the last element. – nevets1219 May 27 '09 at 09:27
  • 3
    - 1 I don't think that answer the question. It is not comparing each item with the next one. – odwl 0 secs ago – odwl May 27 '09 at 10:04
  • 6
    I think I did. Author said he would like to do X, then asked how he can do Y. I answered how he can do Y. That he accepted my answer would indicate I answered the question he asked, if not the question he _really_ wanted to ask. Asker is welcome to demote this answer. – freespace May 27 '09 at 11:35
  • 11
    Just because the OP should have asked another question in the first, does not mean that his question and this answer are not very useful to others. +1 – Prof. Falken Sep 19 '12 at 07:38
  • I don't know what everyone else is talking about - this answers question quite well and is very, very efficient classic Python code! kudos! – rickcnagy Sep 26 '13 at 01:43
  • 1
    I think after (considerable) hindsight some grief and a few downvotes was worth it in the end :) – David Sykes Jan 30 '14 at 14:11
  • 3
    You mention that this does not work for generators. What's the alternative when `y` is a generator? – Joost Oct 18 '15 at 13:13
  • 3
    Doesnt this create a new list? Seems wasteful. – Sush Jun 25 '18 at 21:45
  • @Sush Why would it create a new list? Seems like a dumb interpreter. – Mehdi Charife May 29 '23 at 15:21
61

the easiest way to compare the sequence item with the following:

for i, j in zip(a, a[1:]):
     # compare i (the current) to j (the following)
SilentGhost
  • 307,395
  • 66
  • 306
  • 293
  • 4
    Actually, you can omit the first slice, since zip truncates the longer list to the length of the shorter. This will save you one list creation. (Just in case you are dealing with huge lists. But in that case, you should follow Ants Aasma's approach, which does not copy anything.) – bayer May 27 '09 at 09:57
21

If you want to get all the elements in the sequence pair wise, use this approach (the pairwise function is from the examples in the itertools module).

from itertools import tee, izip, chain

def pairwise(seq):
    a,b = tee(seq)
    b.next()
    return izip(a,b)

for current_item, next_item in pairwise(y):
    if compare(current_item, next_item):
        # do what you have to do

If you need to compare the last value to some special value, chain that value to the end

for current, next_item in pairwise(chain(y, [None])):
Ants Aasma
  • 53,288
  • 15
  • 90
  • 97
  • please note, that use of next for variable name shadows built-in – SilentGhost May 27 '09 at 10:13
  • 1
    I personally don't mind shadowing less used builtins when the scope of the variable is small and the name is good for readability. Nevertheless edited the variable names to maintain good coding practices. – Ants Aasma May 27 '09 at 11:25
8

if you meant comparing nth item with n+1 th item in the list you could also do with

>>> for i in range(len(list[:-1])):
...     print list[i]>list[i+1]

note there is no hard coding going on there. This should be ok unless you feel otherwise.

Perpetualcoder
  • 13,501
  • 9
  • 64
  • 99
  • 4
    You could replace len(list[:-1]) with len(list) - 1 to avoid a list copy. And avoid using a variable called list... – Remy Blank May 27 '09 at 13:31
2

This answers what the OP should have asked, i.e. traverse a list comparing consecutive elements (excellent SilentGhost answer), yet generalized for any group (n-gram): 2, 3, ... n:

zip(*(l[start:] for start in range(0, n)))

Examples:

l = range(0, 4)  # [0, 1, 2, 3]

list(zip(*(l[start:] for start in range(0, 2)))) # == [(0, 1), (1, 2), (2, 3)]
list(zip(*(l[start:] for start in range(0, 3)))) # == [(0, 1, 2), (1, 2, 3)]
list(zip(*(l[start:] for start in range(0, 4)))) # == [(0, 1, 2, 3)]
list(zip(*(l[start:] for start in range(0, 5)))) # == []

Explanations:

  • l[start:] generates a a list/generator starting from index start
  • *list or *generator: passes all elements to the enclosing function zip as if it was written zip(elem1, elem2, ...)

Note:

AFAIK, this code is as lazy as it can be. Not tested.

Community
  • 1
  • 1
juanmirocks
  • 4,786
  • 5
  • 46
  • 46
2

To compare each item with the next one in an iterator without instantiating a list:

import itertools
it = (x for x in range(10))
data1, data2 = itertools.tee(it)
data2.next()
for a, b in itertools.izip(data1, data2):
  print a, b
odwl
  • 2,095
  • 2
  • 17
  • 15
  • 2
    that's exactly what was suggested by Ants Aasma http://stackoverflow.com/questions/914715/python-looping-through-all-but-the-last-item-of-a-list/914786#914786 – SilentGhost May 27 '09 at 10:22