FarmerGedden
FarmerGedden

Reputation: 1201

Iterate through Python list and do something on last element

I'm looking for a pythonic way to iterate through a list and do something on the last (and only the last) element. There are two ways I can see to do this, of which I would guess the second is best:

for item in a_list:
    #do something to every element
    if a_list.index(item) == len(a_list) - 1:
        # do something to the last one

and

for n, item in enumerate(a_list):
   #do something to every element
   if n == len(a_list) - 1 :
       # do something to the last one

However, I wonder if there is a way of doing it without calling len() on a list I'm already iterating over. I'm quite happy, by the way, to be told that this isn't something I should worry about.

Upvotes: 0

Views: 8522

Answers (6)

dawg
dawg

Reputation: 103844

Consider:

li[:]=[do_somthing(item) for item in li]  # something to every item in place
li[-1]=something_extra(li[-1])            # additional to last item

vs

for i, item in enumerate(li):
    li[i]=do_somthing(item)
    if i==len(li)-1:
        li[i]=something_extra(item)

If you time these, you can see this is the fastest way:

def do_something(e):
    return e*2

def something_extra(e):
    return e/2

def f1(li):
    for i, item in enumerate(li):
        li[i]=do_something(item)
        if i==len(li)-1:
            li[i]=something_extra(item)

def f2(li):
    li[:]=[do_something(item) for item in li]
    li[-1]=something_extra(li[-1])

def f3(li):
    for i, item in enumerate(li):
        li[i]=do_something(item)
    li[i]=something_extra(item)

if __name__ == '__main__':
    import timeit
    for f in (f1,f2,f3):
        t=timeit.timeit("f(range(1000))", 
                         setup="from __main__ import f,do_something,something_extra", 
                         number=10000)
        print '{}: {:6.3} seconds'.format(f.__name__, t)

On my (iMac) machine:

f1:   2.95 seconds
f2:   1.45 seconds
f3:   1.97 seconds

Upvotes: 0

user2555451
user2555451

Reputation:

You can use the else block of a for-loop:

>>> for i in [1, 2, 3, 4, 5]:
...     print(i)
... else:
...     print(i**2)
...
1
2
3
4
5
25
>>>

As you can see, an operation is performed on each element in the list but the last one undergoes an extra operation.

Note too that the else block will only be run if the loop exits normally without encountering a break statement. This behavior seems proper because, if a break statement was encountered, then the loop was explicitly exited and we are done with the list.

Upvotes: 2

mgilson
mgilson

Reputation: 309929

for item in lst:
   do_something_to(item)
else:
   do_something_extra_special_to_last(item)

Here I just assume that you want to do something extra to the last item (the normal action will still be taken on it beforehand). I also assume you aren't hitting any break statements (in that case else won't execute). Of course, you don't really need else:

for item in lst:
    do_something_to(item)
do_something_extra_special_to_last(item)

should work too since the loop variable "leaks" into the enclosing scope and if there are breaks that you're worried about and you really are looping over a sequence, why not:

for item in lst:
   do_something_to(item)
do_something_extra_special_to_last(lst[-1])

Upvotes: 11

jonrsharpe
jonrsharpe

Reputation: 122032

I would certainly prefer the second version of the two you present; index could cause problems if there are duplicates in the list and is an O(n) operation on every iteration, whereas len is O(1).

Generally, though, as you want to do something additional (not different) to the last item, I would just make it a separate step after the for loop:

for item in lst:
    # do something to every element
# do something to lst[-1]

This will work even if there is a break (unlike using else) and affects the last item in the list not the last item iterated over - this may or may not be desired behaviour.

Upvotes: 1

aIKid
aIKid

Reputation: 28292

You're making up problems :) There really isn't any with your approach.

If you want to loop, you can find the length. And then access the last thing. Or just do the loop, then do something with a_list[-1]. Fancy way, use for-else - you can google it. But then again, really, there is nothing wrong with your code.

Upvotes: 4

vminof
vminof

Reputation: 121

You can use this:

a_list[-1]

to access last element

Upvotes: 1

Related Questions