Execute Program

Python for Programmers: Negative Indexing

Welcome to the Negative Indexing lesson!

This lesson is shown as static text below. However, it's designed to be used interactively. Click the button below to start!

  • We can get the last element of a list by computing the last index. In a list with 3 elements, the last index is 2.

  • >
    ingredients = ["milk", "flour", "eggs"]
    ingredients[len(ingredients) - 1]
    Result:
    'eggs'Pass Icon
  • That works, but Python makes this easier with some syntactic sugar. We can get the last element in a list with ingredients[-1], without needing to use len at all.

  • >
    ingredients = ["milk", "flour", "eggs"]
    ingredients[-1]
    Result:
    'eggs'Pass Icon
  • Take a moment to compare the final lines of the last two code examples: ingredients[len(ingredients) - 1] vs. ingredients[-1]. Negative indexing syntax is quite terse!

  • Negative indexing works for more than just -1. some_list[-2] gives us the second-to-last element. some_list[-3] gives us the third-from-the-last element, and so on.

  • >
    numbers = [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
    numbers[-6]
    Result:
    6Pass Icon
  • Negative indexing also works in assignments. For example, the assignment some_list[-1] = ... replaces the last element of the list.

  • >
    ingredients = ["eggs", "flour", "water"]
    ingredients[-1] = "milk"
    ingredients
    Result:
    ['eggs', 'flour', 'milk']Pass Icon
  • Negative indexing can feel strange at first. Here are two ways to think about it.

  • The first way is to see negative indexing as "counting backwards" from the end of the list. This is a bit strange, because negative indexing starts at -1, so it's not the same as zero-indexing. But the fact that some_list[-3] gives us the third element from the end is helpful.

  • The second way is to think of an index like -3 as shorthand for len(some_list) - 3. We can always think of some_list[-3] as some_list[len(some_list) - 3].

  • >
    letters = ["A", "B", "C", "D"]
    letters[-2] == letters[len(letters) - 2]
    Result:
    TruePass Icon
  • Both of these mental models work well. You may prefer one of them, or you may switch between them depending on the situation.

  • When a negative index doesn't exist in the list, we get an IndexError. This matches the behavior that we already saw for regular, non-negative indexes. For example, if we have a list of 2 elements, -2 is a valid index but -3 isn't.

  • >
    students = ["Amir", "Betty"]
    students[-3]
    Result:
    IndexError: list index out of rangePass Icon
  • The possible indexes for a non-empty list my_list are:

    • All non-negative numbers from 0 to len(my_list) - 1.
    • All negative numbers from -len(my_list) to -1.
  • If a list is empty, we can't index into it at all. It doesn't matter whether we use positive or negative indexes.

  • >
    students = []
    students[-1]
    Result:
    IndexError: list index out of rangePass Icon
  • Here's a code problem:

    Finish the balanced_list function below. It should decide whether a list starts and ends with the same value. Only the first and last list element matter here; the rest of the elements can be anything.

    You can solve this with a single == comparison that uses negative indexing!

    You'll also need to handle the case where the list is empty. (In that case, your function should return True.)

    def balanced_list(the_list):
    return len(the_list) == 0 or the_list[0] == the_list[-1]
    assert balanced_list([]) == True
    assert balanced_list([1]) == True
    assert balanced_list([1, 2]) == False
    assert balanced_list([1, 2, 1]) == True
    assert balanced_list(["d", "r", "i", "e", "d"]) == True
    assert balanced_list(["d", "r", "i", "n", "k"]) == False
    Goal:
    No errors.
    Yours:
    No errors.Pass Icon