By e.tadeu

2009-10-27 11:54:33 8 Comments

I'd like to know the best way (more compact and "pythonic" way) to do a special treatment for the last element in a for loop. There is a piece of code that should be called only between elements, being suppressed in the last one.

Here is how I currently do it:

for i, data in enumerate(data_list):
    if i != len(data_list) - 1:

Is there any better way?

Note: I don't want to make it with hacks such as using reduce. ;)


@AnythingIsFine 2020-01-16 08:30:49

One simple solution that comes to mind would be:

for i in MyList:
    # Check if 'i' is the last element in the list
    if i == MyList[-1]:
        # Do something different for the last
        # Do something for all other elements

A second equally simple solution could be achieved by using a counter:

# Count the no. of elements in the list
ListLength = len(MyList)
# Initialize a counter
count = 0

for i in MyList:
    # increment counter
    count += 1
    # Check if 'i' is the last element in the list
    # by using the counter
    if count == ListLength:
        # Do something different for the last
        # Do something for all other elements

@Aliaksandr Klimovich 2018-03-26 07:48:25

I like the approach of @ethan-t, but while True is dangerous from my point of view.

data_list = [1, 2, 3, 2, 1]  # sample data
L = list(data_list)  # destroy L instead of data_list
while L:
    e = L.pop(0)
    if L:
        print(f'process element {e}')
        print(f'process last element {e}')
del L

Here, data_list is so that last element is equal by value to the first one of the list. L can be exchanged with data_list but in this case it results empty after the loop. while True is also possible to use if you check that list is not empty before the processing or the check is not needed (ouch!).

data_list = [1, 2, 3, 2, 1]
if data_list:
    while True:
        e = data_list.pop(0)
        if data_list:
            print(f'process element {e}')
            print(f'process last element {e}')
    print('list is empty')

The good part is that it is fast. The bad - it is destructible (data_list becomes empty).

Most intuitive solution:

data_list = [1, 2, 3, 2, 1]  # sample data
for i, e in enumerate(data_list):
    if i != len(data_list) - 1:
        print(f'process element {e}')
        print(f'process last element {e}')

Oh yes, you have already proposed it!

@jeroent 2019-07-19 17:37:29

Instead of counting up, you can also count down:

  nrToProcess = len(list)
  for s in list:
    nrToProcess -= 1
    if nrToProcess==0:  # this is the last one

@amolpachpute 2019-02-01 06:46:32

There can be multiple ways. slicing will be fastest. Adding one more which uses .index() method:

>>> l1 = [1,5,2,3,5,1,7,43]                                                 
>>> [i for i in l1 if l1.index(i)+1==len(l1)]                               

@Chris 2018-07-19 11:55:48

For me the most simple and pythonic way to handle a special case at the end of a list is:

for data in data_list[:-1]:

Of course this can also be used to treat the first element in a special way .

@user240515 2017-08-01 22:54:36

Delay the special handling of the last item until after the loop.

>>> for i in (1, 2, 3):
...     pass
>>> i

@Ethan T 2017-05-23 20:04:20

Count the items once and keep up with the number of items remaining:

remaining = len(data_list)
for data in data_list:

    remaining -= 1
    if remaining:

This way you only evaluate the length of the list once. Many of the solutions on this page seem to assume the length is unavailable in advance, but that is not part of your question. If you have the length, use it.

@DerWeh 2017-04-03 13:45:23

The most simple solution coming to my mind is:

for item in data_list:
    except NameError: pass
    new = item
print('The last item: ' + str(new))

So we always look ahead one item by delaying the the processing one iteration. To skip doing something during the first iteration I simply catch the error.

Of course you need to think a bit, in order for the NameError to be raised when you want it.

Also keep the `counstruct

except NameError: pass
    # continue here if no error was raised

This relies that the name new wasn't previously defined. If you are paranoid you can ensure that new doesn't exist using:

    del new
except NameError:

Alternatively you can of course also use an if statement (if notfirst: print(new) else: notfirst = True). But as far as I know the overhead is bigger.

Using `timeit` yields:

    ...: try: new = 'test' 
    ...: except NameError: pass
100000000 loops, best of 3: 16.2 ns per loop

so I expect the overhead to be unelectable.

@Palza 2016-11-04 03:56:14

if the items are unique:

for x in list:
    if x == list[-1]:

other options:

pos = -1
for x in list:
    pos += 1
    if pos == len(list) - 1:

for x in list:
#code - e.g. print x

if len(list) > 0:
    for x in list[:-1]
    for x in list[-1]:

@Anderson Santos 2016-07-14 14:09:10

Google brought me to this old question and I think I could add a different approach to this problem.

Most of the answers here would deal with a proper treatment of a for loop control as it was asked, but if the data_list is destructible, I would suggest that you pop the items from the list until you end up with an empty list:

while True:
    element = element_list.pop(0)
    if not element:

you could even use while len(element_list) if you don't need to do anything with the last element. I find this solution more elegant then dealing with next().

@tsf144 2016-01-08 21:51:37

if you are going through the list, for me this worked too:

for j in range(0, len(Array)):
    if len(Array) - j > 1:

@Ferdinand Beyer 2009-10-27 12:02:28

Most of the times it is easier (and cheaper) to make the first iteration the special case instead of the last one:

first = True
for data in data_list:
    if first:
        first = False


This will work for any iterable, even for those that have no len():

file = open('/path/to/file')
for line in file:

    # No way of telling if this is the last line!

Apart from that, I don't think there is a generally superior solution as it depends on what you are trying to do. For example, if you are building a string from a list, it's naturally better to use str.join() than using a for loop “with special case”.

Using the same principle but more compact:

for i, line in enumerate(data_list):
    if i > 0:

Looks familiar, doesn't it? :)

For @ofko, and others who really need to find out if the current value of an iterable without len() is the last one, you will need to look ahead:

def lookahead(iterable):
    """Pass through all values from the given iterable, augmented by the
    information if there are more values to come after the current one
    (True), or if it is the last value (False).
    # Get an iterator and pull the first value.
    it = iter(iterable)
    last = next(it)
    # Run the iterator to exhaustion (starting from the second value).
    for val in it:
        # Report the *previous* value (more to come).
        yield last, True
        last = val
    # Report the last value.
    yield last, False

Then you can use it like this:

>>> for i, has_more in lookahead(range(3)):
...     print(i, has_more)
0 True
1 True
2 False

@e.tadeu 2009-10-27 12:11:30

True, this way seems better than mine, at least it don't need to use enumerate and len.

@Adam Matan 2009-10-27 12:13:24

Yes, but it adds another if which could be avoided if the loop was split into two loops. However, this is relevant only when iterating a huge data list.

@e.tadeu 2009-10-27 12:15:26

The problem with splitting into two loops is that it either violates DRY or it forces you to define methods.

@Olivier Pons 2015-12-06 16:29:28

I really try to understand your last example (which works flawlessly in my code), but I dont understand how it works (the idea behind)

@Ferdinand Beyer 2015-12-06 20:50:37

@OlivierPons You need to understand Python's iterator protocol: I get an iterator for an object, and retrieve the first value with next(). Then I exploit that an iterator is iterable by itself, so I can use it in the for loop until exhaustion, iteration from the second to the last value. During this I keep the current value I retrieved from the iterator locally and yield the last one instead. This way I know there is one more value to come. After the for loop, I have reported every value but the last one.

@Roger Dahl 2015-06-23 03:27:22

Use slicing and is to check for the last element:

for data in data_list:
    if not data is data_list[-1]:

Caveat emptor: This only works if all elements in the list are actually different (have different locations in memory). Under the hood, Python may detect equal elements and reuse the same objects for them. For instance, for strings of the same value and common integers.

@BeckmaR 2015-06-17 07:46:09

Although that question is pretty old, I came here via google and I found a quite simple way: List slicing. Let's say you want to put an '&' between all list entries.

s = ""
l = [1, 2, 3]
for i in l[:-1]:
    s = s + str(i) + ' & '
s = s + str(l[-1])

This returns '1 & 2 & 3'.

@Bryan Oakley 2016-01-21 16:45:41

You've just reimplemented the join function: `" & ".join([str(x) for x in l])

@plhn 2017-04-10 06:30:02

string concatenation is somewhat inefficient. If len(l)=1000000 in this example, program will run for a while. appendis recommended afaik. l=[1,2,3]; l.append(4);

@e-satis 2009-10-27 12:15:19

There is nothing wrong with your way, unless you will have 100 000 loops and wants save 100 000 "if" statements. In that case, you can go that way :

iterable = [1,2,3] # Your date
iterator = iter(iterable) # get the data iterator

try :   # wrap all in a try / except
    while 1 : 
        item = 
        print item # put the "for loop" code here
except StopIteration, e : # make the process on the last element here
    print item

Outputs :


But really, in your case I feel like it's overkill.

In any case, you will probably be luckier with slicing :

for item in iterable[:-1] :
    print item
print "last :", iterable[-1]

last : 3

or just :

for item in iterable :
    print item
print iterable[-1]

last : 3

Eventually, a KISS way to do you stuff, and that would work with any iterable, including the ones without __len__ :

item = ''
for item in iterable :
    print item
print item



If feel like I would do it that way, seems simple to me.

@e.tadeu 2009-10-27 12:23:24

But note that iterable[-1] will not work to all iterables (such as generator that do not have len)

@Ferdinand Beyer 2009-10-27 12:27:31

If all you want is to access the last item after the loop, simply use item instead of re-calculating it using list[-1]. But nevertheless: I don't think this is what the OP was asking for, was it?

@PaulMcG 2009-10-28 02:16:29

Re: iterable.__iter__() - please don't call __ functions directly. Should be iter(iterable).

@Andrew Dalke 2009-10-27 20:32:51

This is similar to Ants Aasma's approach but without using the itertools module. It's also a lagging iterator which looks-ahead a single element in the iterator stream:

def last_iter(it):
    # Ensure it's an iterator and get the first field
    it = iter(it)
    prev = next(it)
    for item in it:
        # Lag by one item so I know I'm not at the end
        yield 0, prev
        prev = item
    # Last item
    yield 1, prev

def test(data):
    result = list(last_iter(data))
    if not result:
    if len(result) > 1:
        assert set(x[0] for x in result[:-1]) == set([0]), result
    assert result[-1][0] == 1

test([1, 2])

for is_last, item in last_iter("Hi!"):
    print is_last, item

@Anon 2009-10-27 13:39:40

Assuming input as an iterator, here's a way using tee and izip from itertools:

from itertools import tee, izip
items, between = tee(input_iterator, 2)  # Input must be an iterator.
first =
do_to_every_item(first)  # All "do to every" operations done to first item go here.
for i, b in izip(items, between):
    do_between_items(b)  # All "between" operations go here.
    do_to_every_item(i)  # All "do to every" operations go here.


>>> def do_every(x): print "E", x
>>> def do_between(x): print "B", x
>>> test_input = iter(range(5))
>>> from itertools import tee, izip
>>> items, between = tee(test_input, 2)
>>> first =
>>> do_every(first)
E 0
>>> for i,b in izip(items, between):
...     do_between(b)
...     do_every(i)
B 0
E 1
B 1
E 2
B 2
E 3
B 3
E 4

@S.Lott 2009-10-27 13:38:36

The 'code between' is an example of the Head-Tail pattern.

You have an item, which is followed by a sequence of ( between, item ) pairs. You can also view this as a sequence of (item, between) pairs followed by an item. It's generally simpler to take the first element as special and all the others as the "standard" case.

Further, to avoid repeating code, you have to provide a function or other object to contain the code you don't want to repeat. Embedding an if statement in a loop which is always false except one time is kind of silly.

def item_processing( item ):
    # *the common processing*

head_tail_iter = iter( someSequence )
head =
item_processing( head )
for item in head_tail_iter:
    # *the between processing*
    item_processing( item )

This is more reliable because it's slightly easier to prove, It doesn't create an extra data structure (i.e., a copy of a list) and doesn't require a lot of wasted execution of an if condition which is always false except once.

@Ferdinand Beyer 2009-11-04 18:41:45

Function calls are way slower then if statements so the “wasted execution” argument does not hold.

@S.Lott 2009-11-04 18:43:11

I'm not sure what the speed difference between function call and if-statement has to do with anything. The point is that this formulation has no if-statement that's always false (except once.)

@Ferdinand Beyer 2009-11-04 18:52:02

I interpreted your statement “…and doesn't require a lot of wasted execution of an if condition which is always false except once” as “…and is faster since it saves a couple of ifs”. Obviously you are just refering to “code cleanliness”?

@Markus von Broady 2019-09-25 07:11:48

Is defining a function instead of using an if statement really considered cleaner by Python community?

@Ants Aasma 2009-10-27 13:17:21

You can use a sliding window over the input data to get a peek at the next value and use a sentinel to detect the last value. This works on any iterable, so you don't need to know the length beforehand. The pairwise implementation is from itertools recipes.

from itertools import tee, izip, chain

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

def annotated_last(seq):
    """Returns an iterable of pairs of input item and a boolean that show if
    the current item is the last item in the sequence."""
    MISSING = object()
    for current_item, next_item in pairwise(chain(seq, [MISSING])):
        yield current_item, next_item is MISSING:

for item, is_last_item in annotated_last(data_list):
    if is_last_item:
        # current item is the last item

@xtofl 2009-10-27 12:11:17

Is there no possibility to iterate over all-but the last element, and treat the last one outside of the loop? After all, a loop is created to do something similar to all elements you loop over; if one element needs something special, it shouldn't be in the loop.

(see also this question: does-the-last-element-in-a-loop-deserve-a-separate-treatment)

EDIT: since the question is more about the "in between", either the first element is the special one in that it has no predecessor, or the last element is special in that it has no successor.

@e.tadeu 2009-10-27 12:16:46

But the last element should be treated similar to every other element in the list. The problem is the thing that should be done only between elements.

@xtofl 2009-10-27 12:39:41

In that case, the first one is the only one without a predecessor. Take that one apart, and loop over the rest of the list general code.

@Bartek 2009-10-27 12:05:19

If you're simply looking to modify the last element in data_list then you can simply use the notation:


However, it looks like you're doing more than that. There is nothing really wrong with your way. I even took a quick glance at some Django code for their template tags and they do basically what you're doing.

@e.tadeu 2009-10-27 12:20:10

I'm not modifying it, I'm using it to do something

@spacetyper 2015-08-28 20:29:56

@e.tadeu it doesn't even matter if you're modifying it or not. Changing your if statement to: if data != datalist[-1]: and keeping everything else the same would be the best way to code this in my opinion.

@Ark-kun 2017-12-29 14:16:22

@spacetyper This breaks when the last value is non-unique.

Related Questions

Sponsored Content

5 Answered Questions

[SOLVED] What is the Python 3 equivalent of "python -m SimpleHTTPServer"

36 Answered Questions

[SOLVED] What is the most "pythonic" way to iterate over a list in chunks?

26 Answered Questions

[SOLVED] Pythonic way to create a long multi-line string

22 Answered Questions

[SOLVED] Is there a way to create multiline comments in Python?

11 Answered Questions

[SOLVED] Getting the last element of a list

  • 2009-05-30 19:28:53
  • Janusz
  • 2103275 View
  • 2058 Score
  • 11 Answer
  • Tags:   python list indexing

20 Answered Questions

[SOLVED] What are metaclasses in Python?

10 Answered Questions

[SOLVED] Proper way to declare custom exceptions in modern Python?

23 Answered Questions

[SOLVED] Is there a way to run Python on Android?

12 Answered Questions

[SOLVED] What's the canonical way to check for type in Python?

  • 2008-09-30 11:00:10
  • Herge
  • 870557 View
  • 1273 Score
  • 12 Answer
  • Tags:   python types

Sponsored Content