# Lists

## Contents

# Lists#

*Jesse London*

Modern computing would be inconceivable without the ability to interact with a *collection* of multiple values at once, and more specifically the ordered *sequence* of values. In Python, the most common of these data types is called the `list`

.

Lists are syntactically defined using commas to separate their constituent elements, and enclosed by square brackets.

```
primes_abridged = [2, 3, 5, 7, 11, 13, 17, 19, 23]
primes_abridged
```

```
[2, 3, 5, 7, 11, 13, 17, 19, 23]
```

## Identifying elements#

Lists not only enable us to address a sequence of values at once. They also permit us to refer to their elements:

```
primes_abridged[0]
```

```
2
```

```
primes_abridged[5]
```

```
13
```

Above, we retrieved individual elements from our list, by indicating the *index* of the element to retrieve – after the name assigned to the list, and with the index itself enclosed in square brackets.

Note

We referred to the *first* element of our list using the index `0`

, and to the *sixth* with the index `5`

. In computer programming, you can think of this reference not as the “number” or the “count” of the element, but rather as an “offset” from the beginning of the list.

Even the index, or offset, `-1`

is valid, and this is the general way to refer to the last element of the list:

```
primes_abridged[-1]
```

```
23
```

## Slices#

We can also retrieve a subset of the elements of our list, for example using the *slice*.

```
primes_really_abridged = primes_abridged[2:5]
primes_really_abridged
```

```
[5, 7, 11]
```

In the syntax of the slice, we indicated that we would like to construct a new list, consisting of the elements at indices `2`

through `4`

, ending *before* index `5`

.

That is, slices are constructed from a generic *range*. This range may be bounded or unbounded. The lower bound, or *start*, is always *inclusive*. The upper bound, or *end*, is always *exclusive*.

The full signature of the slice includes a start, end and *step*. All of these arguments are optional, and their defaults are to start with the first element of the list, to end after the last element of the list, and to “step” through the elements one-by-one. As such, the following three expressions evaluate the same.

```
primes_abridged[0:9:1]
```

```
[2, 3, 5, 7, 11, 13, 17, 19, 23]
```

```
primes_abridged[:]
```

```
[2, 3, 5, 7, 11, 13, 17, 19, 23]
```

```
primes_abridged[::]
```

```
[2, 3, 5, 7, 11, 13, 17, 19, 23]
```

We can of course supply some arguments and omit others.

Let’s slice our list starting with its second element – at index `1`

.

```
primes_abridged[1:]
```

```
[3, 5, 7, 11, 13, 17, 19, 23]
```

…Or ending *before* index `3`

.

```
primes_abridged[:3]
```

```
[2, 3, 5]
```

We can even specify negative indices.

Let’s start with the last element.

```
primes_abridged[-1:]
```

```
[23]
```

…Or, construct a list consisting of only the third-to-last and second-to-last elements.

```
primes_abridged[-3:-1]
```

```
[17, 19]
```

A slice can also indicate a step other than `1`

, such that some elements are stepped over, or skipped.

```
every_other_prime_abridged = primes_abridged[::2]
every_other_prime_abridged
```

```
[2, 5, 11, 17, 23]
```

We can even step through the list *backwards*.

```
primes_abridged[-1::-1]
```

```
[23, 19, 17, 13, 11, 7, 5, 3, 2]
```

Above, we started with the index of the last element, and told the slice to *decrement* this index by one for each subsequent element. (And, given this negative step, the list knew by default that the last element should be the first.)

## Aggregation#

Most important, lists enable us to instruct the computer to apply an operation to each element of the list in sequence.

And, most simply, we can count the number of elements in our list.

```
len(primes_abridged)
```

```
9
```

Better yet, we can `sum`

the elements.

```
sum(primes_abridged)
```

```
100
```

Combining the two of these, we can compute an average or mean.

```
sum(primes_abridged) / len(primes_abridged)
```

```
11.11111111111111
```

The elements of multiple lists may be combined – or *concatenated* – forming a new list, with the addition operator.

```
primes_abridged + [29, 31, 37, 41]
```

```
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41]
```

And a list may even be trivially combined with itself – with the multiplication operator!

```
3 * primes_really_abridged
```

```
[5, 7, 11, 5, 7, 11, 5, 7, 11]
```

## Mutation & Methods#

A list may be *mutated* – that is, manipulated *without* creating a new list – thanks in part to list methods.

Note

Mutation is is also known as manipulation “in place.”

Making changes to a list of data, without creating a new list and assigning a new name, is less straight-forward, and may be prone to error.

However, mutation can also be integral to the process of constructing or building a list; (and, such methods can be useful when computing performance becomes important).

We might extend our list `primes_really_abridged`

with the `append`

method.

```
primes_really_abridged.append(13)
```

…What happened? The above expression had no output – (literally, it evaluated to `None`

, which is hidden by default).

Many of Python’s built-in mutational methods have no output, because none (or `None`

!) is necessary.

Indeed, `append`

had the desired effect. The prime `13`

has been added to the end of our list.

```
primes_really_abridged
```

```
[5, 7, 11, 13]
```

Let’s continue to make our list a little less abridged with the `insert`

method.

```
primes_really_abridged.insert(0, 3)
```

```
primes_really_abridged
```

```
[3, 5, 7, 11, 13]
```

Again, our mutation expression had no output.

But this time, we’ve added an element to the beginning of our list, by *inserting* it *before* the element that was at index `0`

.

Let’s add some more.

```
primes_really_abridged.append(19)
primes_really_abridged.append(23)
primes_really_abridged
```

```
[3, 5, 7, 11, 13, 19, 23]
```

Whoops – we forgot the prime `17`

.

Luckily, elements may be inserted into any position of a list.

But where do we need to insert `17`

? Let’s ask the list which index is `19`

– appropriately, with the method `index`

.

```
primes_really_abridged.index(19)
```

```
5
```

Unlike `insert`

and `append`

, `index`

does not mutate the list. It only returns the requested value.

Now we can put `17`

in its proper place.

```
missing_index = primes_really_abridged.index(19)
primes_really_abridged.insert(missing_index, 17)
primes_really_abridged
```

```
[3, 5, 7, 11, 13, 17, 19, 23]
```

Note that the `insert`

method accepts *any* index.

This includes negative indices.

```
primes_really_abridged.append(37)
primes_really_abridged
```

```
[3, 5, 7, 11, 13, 17, 19, 23, 37]
```

Huh, we skipped a prime again.

```
primes_really_abridged.insert(-1, 31)
primes_really_abridged
```

```
[3, 5, 7, 11, 13, 17, 19, 23, 31, 37]
```

Almost there….

```
primes_really_abridged.insert(-2, 29)
primes_really_abridged
```

```
[3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37]
```

That’s better.

`insert`

can even get a little silly….

```
primes_really_abridged.insert(1_000_000, 41)
primes_really_abridged
```

```
[3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41]
```

Above, we asked `insert`

to place the element `41`

*before* any element at the index for 1,000,000.

What it did was place this value at the end of the list – that is at index `11`

.

```
primes_really_abridged[11]
```

```
41
```

In other words, `insert`

did what we asked it to do.

Also note from the above, list elements must be *contiguous* – elements must be positioned one after the other, and referred to by a continuous range of indices – and not *sparse*.

One list method which both mutates the list and returns a value is `pop`

.

The `pop`

method *removes* an element from the list and returns this value.

This can be useful in moving elements from one list to another, or in otherwise making use of removed elements.

By default, `pop`

removes the last element from the list.

```
primes_really_abridged.pop()
```

```
41
```

```
primes_really_abridged
```

```
[3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37]
```

`pop`

may optionally be given the index of an element to remove.

```
primes_really_abridged.pop(0)
```

```
3
```

```
primes_really_abridged
```

```
[5, 7, 11, 13, 17, 19, 23, 29, 31, 37]
```

Because lists are contiguous, and because the index of their first element is always `0`

, each element removed shifts the indices of the elements that followed it.

As such, when we remove the element at index `3`

, the element that followed it takes on that index, *etc*.

```
primes_really_abridged.pop(3)
primes_really_abridged.pop(3)
primes_really_abridged.pop(3)
primes_really_abridged.pop(3)
primes_really_abridged.pop(3)
primes_really_abridged.pop(3)
primes_really_abridged.pop(3)
primes_really_abridged
```

```
[5, 7, 11]
```

Of course, the above became fairly verbose.

We’ll learn more, generic Python operations for mutating lists, and for concisely manipulating collections of data, in subsequent chapters.

## Other lists#

So far we’ve only considered lists of numbers, but in fact list elements may refer to values of any type – and even of multiple types at once.

```
planets = [
'Mercury',
'Venus',
'Earth',
'Mars',
'Jupiter',
'Saturn',
'Uranus',
'Neptune',
]
```

In the above, we’ve constructed a list of the `planets`

, whose elements are, of course, strings.

Depending on when you attended grade school, you may prefer the following planetary listing:

```
planets + ['Pluto']
```

```
['Mercury',
'Venus',
'Earth',
'Mars',
'Jupiter',
'Saturn',
'Uranus',
'Neptune',
'Pluto']
```

But this needn’t worry the International Astronomical Union! We didn’t use `append()`

, so the `planets`

are safe.

```
planets
```

```
['Mercury', 'Venus', 'Earth', 'Mars', 'Jupiter', 'Saturn', 'Uranus', 'Neptune']
```

Lists can even contain other lists of data.

```
# distances from the sun, millions of miles:
planetary_distances = [
['Mercury', 36],
['Venus', 67.2],
['Earth', 93],
['Mars', 141.6],
['Jupiter', 483.6],
['Saturn', 886.7],
['Uranus', 1_784.0],
['Neptune', 2_794.4],
]
planetary_distances
```

```
[['Mercury', 36],
['Venus', 67.2],
['Earth', 93],
['Mars', 141.6],
['Jupiter', 483.6],
['Saturn', 886.7],
['Uranus', 1784.0],
['Neptune', 2794.4]]
```

In the above collection, we’ve combined lists, strings, integers and floats!

This kind of structure, if constructed *arbitrarily*, can be difficult to use; but, constructed consistently, this is the basis of computational data and data science.

But lists are not the only kind of useful collection available to us in Python, and we’ll explore a few!