11

I want to do something different to the the first item in a list. What is the most pythonic way of doing so?

for item in list:
    # only if its the first item, do something

    # otherwise do something else
Dap
  • 2,309
  • 5
  • 32
  • 44

5 Answers5

21

A few choices, in descending order of Pythonicity:

for index, item in enumerate(lst): # note: don't use list
    if not index: # or if index == 0:
        # first item
    else:
        # other items

Or:

first = True
for item in lst:
    if first:
        first = False
        # first item 
    else:
        # other items 

Or:

for index in range(len(lst)):
    item = lst[i]
    if not index:
        # first item
    else:
        # other items
jonrsharpe
  • 115,751
  • 26
  • 228
  • 437
  • 4
    One advantage of using `enumerate` over several of the other options is that it doesn't matter whether or not the object being iterated over supports indexing. – DSM Jan 08 '14 at 21:15
  • 3
    I like enumerate but I don't know if I'd use `if not index`. `if index==0` is more explicit. – Adam Smith Jan 08 '14 at 21:17
  • 3
    @adsmith: PEP 8 says otherwise. And there are examples of exactly `if not index:` in the stdlib. – abarnert Jan 08 '14 at 21:17
  • 1
    All variants require if in the body of the cycle. Very inefficient – volcano Jan 08 '14 at 21:33
  • @volcano: Really? You've tested it? Because normally, at least in CPython, the cost of `if myint:` is a couple of orders of magnitude less than the cost of calling `next` on an iterator, so you'd barely even be able to measure it. If you have a specific example where it really is "very inefficient", post the data. – abarnert Jan 08 '14 at 21:53
  • @abarnert, my another problem with this solution - as opposed to user2981639's and your last - code within a cycle that handles special cases. I try to avoid those. – volcano Jan 08 '14 at 22:07
  • 1
    @volcano: I don't know what you mean by "a cycle of several thousands". If you mean a loop over several thousand values, then you've got several thousand calls to `next`, each of which takes a couple orders of magnitude longer than each `if` statement, so the proportion is unchanged. – abarnert Jan 08 '14 at 22:18
10

You can create an iterator over the list using iter(), then call next() on it to get the first value, then loop on the remainder. I find this a quite elegent way to handle files where the first line is the header and the rest is data, i.e.

list_iterator = iter(lst)

# consume the first item
first_item = next(list_iterator)

# now loop on the tail
for item in list_iterator:
    print(item)
David Waterworth
  • 2,214
  • 1
  • 21
  • 41
  • 1
    The explanation is a little off - you do not convert list to iterator, you create iterator over list. Upvoted for efficiency and elegance – volcano Jan 08 '14 at 21:37
  • Good point, I've edited to clarify. Also what I like is calling iter(iter(list)) still returns the inner so you don't need to know if lst is a list object, or a list_iterator (or other iterable) – David Waterworth Jan 08 '14 at 21:42
  • 1
    I like it but it may not be the best solution in all situations, for example if the loop contains a few statements which should be executed for the first item as well as for other items. In such cases, the accepted answer by @jonrsharpe is probably the best indeed. – PhiM Aug 25 '23 at 17:29
6
do_something_with_first_item(lst[0])
for item in lst[1:]:
    do_something_else(item)

Or:

is_first_item = True
for item in lst:
    if is_first_item:
        do_something_with_first_item(item)
        is_first_item = False
    else:
        do_something_else(item)

Do not use list as a variable name, because this shadows the built-in function list().

The enumerate-based solution in jonrsharpe's answer is superior to this. You should probably use that instead.

senshin
  • 10,022
  • 7
  • 46
  • 59
2

Use a flag that you change after processing the first item. For example:

first = True
for item in my_list:
    if first:
        # Processing unique to the first item
        first = False
    else:
        # Processing unique to other items
    # Shared processing

You could also just process the first item:

first = my_list.pop(0)
# Process first
for item in my_list:
    # Process item

# Add the first item back to the list at the beginning
my_list.insert(0, first)
thegrinner
  • 11,546
  • 5
  • 41
  • 64
2

jonrsharpe's first version using enumerate is clean and simple, and works with all iterables:

for index, item in enumerate(lst):
    if not index:
        do_something_with_first_item(item)
    else:
        do_something_else(item)

senshin's first solution using lst[0] and lst[1:] is even simpler, but only works with sequences:

do_something_with_first_item(lst[0])
for item in lst[1:]:
    do_something_else(item)

You can get the best of both worlds by using iterators directly:

it = iter(lst)
do_something_with_first_item(next(it))
for item in it:
    do_something_else(item)

But, despite being the best of both worlds, it's actually not quite as simple as either. This is only clearly worth doing if you know you have an iterator (so you can skip the first line), or you need one anyway to do itertools and genexpr and similar stuff to (so you were already going to write the first line). Whether it's worth doing in other cases is more of a style issue.

abarnert
  • 354,177
  • 51
  • 601
  • 671
  • I don't think you have to know you have an iterator or not for the last method. I did a quick check and calling iter() on an iterator seems to return the original iterator - i.e. iter(iter([1,2,3])) and iter([1,2,3]) both return a which iterates the orignal list. So I would use this method in every case - the first is clean but tests the index on every iteration of the loop, the seconds requires an index-able object. – David Waterworth Jan 08 '14 at 21:31
  • @user2981639: Yes, `iter(it)` is guaranteed to return `it` if it's an iterator—that is, in fact, part of the definition of what an iterator is. The point is that if you know it's an iterator, you can skip the first line, making this the simplest solution; if you have a sequence, or don't know what kind of iterable you have, you can't skip the first line, so it may not be the simplest – abarnert Jan 08 '14 at 21:50