Enumerate

Published

2023-07-31

enumerate()

We’ve seen how to iterate over the elements of an iterable in a for loop.

for e in lst:
    print(e)

Sometimes, however, it’s helpful to have both the element and the index of the element at each iteration. One common application requiring an element and the index of the element is in calculating an alternating sum. Alternating sums appear in analysis, number theory, combinatorics, many with real-world applications.

An alternating sum is simply a summation where the signs of terms alternate. Rather than

x_0 + x_1 + x_2 + x_3 + x_4 + x_5 + \ldots

where the signs are all positive, an alternating sum would look like this:

x_0 - x_1 + x_2 - x_3 + x_4 - x_5 + \ldots

Notice that we alternate addition and subtraction.

There are many ways we could implement this. Here’s one rather clunky example (which assumes we have a list of numerics named lst):

alternating_sum = 0

for i in range(len(lst)):
    if i % 2:  # i is odd, then we subtract
        alternating_sum -= lst[i]
    else:
        alternating_sum += lst[i]

This works. Strictly speaking from a mathematical standpoint it is correct, but for i in range(len(lst)) and then using i as an index into lst is considered an “anti-pattern” in Python. (Anti-patterns are patterns that we should avoid.)

So what’s a programmer to do?

enumerate() to the rescue! Python provides us with a handy built-in function called enumerate(). This iterates over all elements in some sequence and yields a tuple of the index and the element at each iteration.

Here’s the same loop implemented using enumerate():

alternating_sum = 0

for i, e in enumerate(lst):
    if i % 2:
        alternating_sum -= e
    else:
        alternating_sum += e

We do away with having to call len(list) and we do away with indexed reads from lst.

Here’s another example, where we wish to perform indexed writes into a list in a loop. Say we wanted to increment every element in a list of numeric values by a constant. Here’s how we can do this with enumerate().

incr = 5
lst = [1, 2, 3, 4]

for i, e in enumerate(lst):
    lst[i] = e + incr 

That’s it! After this code has run, lst has the value [6, 7, 8, 9].

In many cases, use of enumerate() leads to cleaner and more readable code. But how does it work? What, exactly, does enumerate() do?

If we pass some iterable—say a list, tuple, or string—as an argument to enumerate() we get a new iterable object back, one of type enumerate (this is a new type we haven’t seen before). When we iterate over an enumerate object, it yields tuples. The first element of the tuple is the index of the element in the original iterable. The second element of the tuple is the element itself.

That’s a lot to digest at first, so here’s an example:

lst = ['a', 'b', 'c', 'd']
for i, element in enumerate(lst):
    print(f"The element at index {i} is '{element}'.")

This prints:

The element at index 0 is 'a'.
The element at index 1 is 'b'.
The element at index 2 is 'c'.
The element at index 3 is 'd'.

The syntax that we use above is tuple unpacking (which we saw in an earlier chapter). When using enumerate() this comes in really handy. We use one variable to hold the index and one to hold the element. enumerate() yields a tuple, and we unpack it on the fly to these two variables.

Let’s dig a little deeper using the Python shell.

>>> lst = ['a', 'b', 'c']
>>> en = enumerate(lst)
>>> type(en)       # verify type is `enumerate`
<class 'enumerate'>
>>> for t in en:   # iterate `en` without tuple unpacking
...    print(t)
... 
(0, 'a')
(1, 'b')
(2, 'c')

So you see, what’s yielded at each iteration is a tuple of index and element. Pretty cool, huh?

Now that we’ve learned a little about enumerate() let’s revisit the alternating sum example:

alternating_sum = 0

for i, e in enumerate(lst):
    if i % 2:
        alternating_sum -= e
    else:
        alternating_sum += e

Recall that we’d assumed lst is a previously defined list of numeric elements. When we pass lst as an argument to enumerate() we get an enumerate object. When we iterate over this object, we get tuples at each iteration. Here we unpack them to variables i and e. i is assigned the index, and e is assigned the element.

If you need both the element and its index, use enumerate().

Original author: Clayton Cafiero < [given name] DOT [surname] AT uvm DOT edu >

No generative AI was used in producing this material. This was written the old-fashioned way.

This material is for free use under either the GNU Free Documentation License or the Creative Commons Attribution-ShareAlike 3.0 United States License (take your pick).