tags:

views:

84

answers:

6

Assuming I have object_list list which contains objects.

I want to check if my current iteration is is at the first or the last.

for object in object_list:
    do_something
    if first_indexed_element:
        do_something_else
    if last_indexed_element:
        do_another_thing

How can this be achieved? I know that I can use range and count index but if feels clumsy.

Regards

+6  A: 

You can use enumerate():

for i, obj in enumerate(object_list):
    do_something
    if i == 0:
        do_something_else
    if i == len(object_list) - 1:
        do_another_thing

But instead of checking in every iteration which object you are dealing with, maybe something like this is better:

def do_with_list(object_list):
    for obj in object_list:
        do_something(obj)
    do_something_else(object_list[0])
    do_another_thing(object_list[-1])

Imagine you have a list of 100 objects, then you make 198 unnecessary comparisons, because the current element cannot be the first or last element in the list.

But it depends on whether the statements have to be executed in a certain order and what they are doing.


Btw. don't shadow object, it is already an identifier in Python ;)

Felix Kling
`i` will never equal `len(object_list)`.
Amber
@Amber: True, thanks
Felix Kling
+1  A: 
for index, obj in enumerate(object_list):
    do_something
    if index == 0:
        do_something_else
    if index == len(object_list)-1:
        do_another_thing
Amber
Will break if object_list is iterator. It's better to write code that will work with all iterables, not only lists.
Tomasz Wysocki
Not when it makes the code far more complex to read, and you know you're going to be working with lists.
Amber
A: 

You just have to use a counter, no need for range :

Let's say your counter is cpt.

if cpt == 0:
  print "first"

if cpt == len(object_list) - 1:
  print "last"

edit : the enumerate solution may be more elegant.

Guillaume Lebourgeois
A: 
  1. You can make i = 0 and then i++ in iterations. So if i==0 it is first iteration, if i == list.size()-1 than it is last iteration.
  2. There must be smth like indexOf(object), which returns position of element in list. if 0 - than first iteration, if size()-1 than last. But it is expensive.
  3. use enumerate. See Amber or Felix posts.
  4. compare current element to list[0] and to list[-1]. in first case - first iteration, in last case - last iteration. It is expensive too.

So i'd choose 1 or 3.
PS: list.size() is len(list) of course.

foret
Why should 4. be expensive? List access should be `O(1)`.
Felix Kling
Don't know what is O(1), but comparing custom objects, imho, is always slower then comparing numbers (even if they are objects too). Moreover, in this case you should provide equality rules, which can be quite complicated. Moreover, list can contain duplicates, so it can cause errors (it is different point of view, nevertheless you must consider it).
foret
Moreover! : when you try to get element from list, python first find list, then find element at index. if you use number, it must only find number, so 1 operation less. imho - i don;t know python internals.
foret
You are right, comparing objects *can* be expensive if they implement a custom comparison function. But accessing an element in a list is fast.
Felix Kling
+9  A: 
li = iter(object_list)

obj = next(li)

do_first_thing_with(obj)

while True:
    try:
        do_something_with(obj)
        obj = next(li)
    except StopIteration:
        do_final_thing_with(obj)
        break
Autoplectic
+1 for using iterators instead of index numbers. In the OP's question, all objects are processed with do_something, and special processing is done with the first and last. In your code, you do the special processing for the first item, but not the every-item processing. I think you just need to reverse the 2 statements in your try: clause to get the desired behavior.
Paul McGuire
Quite complicated. Not exactly that author wants (`do_first_thing_with` should be called after first `do_something_with`).
Tomasz Wysocki
likely the most efficient solution (+1), but unfortunately not very concise/easy to grok.
wds
A: 
first = True
for o in object_list:
    do_something(o)
    if first:
        first = False
        do_something_with_first(o)
if 'o' in locals():
    do_something_with_last(o)
Tomasz Wysocki