Lists ↩
- List basics
- List slicing
- Adding items to a list
- Removing items from a list
- Sorting lists
- Using sorted() and reversed()
- Creating number sequences
Lists are ordered and mutable collections of non-unique items.
In other programming languages, lists are sometimes called arrays.
List basics
Lists are delimited by square brackets and can contain different types of items:
>>> list1 = [1, -20, "hello", 4.347, 500]
Accessing list items
List items can be accessed by their index or position. In Python and most other programming languages, the first item has index 0
(zero):
>>> list1[0] # first item
1
>>> list1[2] # third item
hello
Negative numbers can be used to access items backwards:
>>> list1[-1] # last item
500
Nested lists
Lists can contain other lists, which can contain other lists, and so on. This is known as nested lists:
>>> list2 = [1, 2, 3, ["a", "b", "c"]]
>>> list3 = [1, 2, 3, ["a", ["A", "B"], "b", [], "c"]]
Items in nested lists can be accessed by ‘chaining’ the indexes of the parent lists and the item index:
>>> list3[-1][1][0]
'A'
Operations with lists
Lists can be added using the +
operator. The result is a new list with the items of the lists concatenated in the given order.
>>> list1 + ['b', 100] + ['abcdef']
[1, -20, 'hello', 4.347, 500, 'b', 100, 'abcdef']
Lists can also be multiplied by integers. The result is equivalent to adding the list to itself n
times:
>>> list1 * 3
[1, -20, 'hello', 4.347, 500, 1, -20, 'hello', 4.347, 500, 1, -20, 'hello', 4.347, 500]
Subtraction and division operations are not supported with lists.
Making copies of a list
Assigning a list to a new variable does not create another list, just a new reference to the same list object.
>>> anotherList = list1
>>> anotherList.append(-9999) # add an item to the list
>>> list1
[1, -20, 'asdsd', 4.347, 500, -9999]
We’ve added an item to anotherList
, and it appeared when we printed list1
. It makes sense once we understand that both variable names point to the same list.
There are different ways to create a copy of a list. One of them is using the built-in function list()
:
>>> aCopy = list(list1)
>>> aCopy.append(9999)
>>> aCopy
[1, -20, 'hello', 4.347, 500, -9999, 9999]
>>> list1
[1, -20, 'hello', 4.347, 500, -9999]
Another way of making a copy of a list is by creating a slice of the whole list (see the next section):
>>> anotherCopy = list1[:]
List slicing
A slice is a continuous range of items in a list. Slicing a list returns a new list.
Consider the following ASCII diagram
+---+---+---+---+---+---+
| P | y | t | h | o | n |
+---+---+---+---+---+---+
Slice position: 0 1 2 3 4 5 6
Index position: 0 1 2 3 4 5
A slice is defined using start and end indexes separated by a colon:
>>> list1 = [1, -20, 'hello', 4.347, 500, 'abcdefg']
>>> list1[2:4] # get a slice from 3nd to 5th items
['hello', 4.347]
The item at the start index is included in the slice, the one at the end index is not.
To start a slice before the first item, use 0
or simply leave out the first index:
>>> list1[:4] # same as: list1[0:4]
[1, -20, 'hello', 4.347]
To finish a slice after the last list item, leave out the second index:
>>> list1[2:]
['hello', 4.347, 500, 'abcdefg']]
Slice indexes can also be negative. We can count items from the end of the list
>>> list1[-2:] # last two items in the list
[500, 'abcdefg']
or exclude some items at the end of the list
>>> list1[:-2] # last two items in the list
[1, -20, 'hello', 4.347] # everything except the last two items
The slicing notation works with any kind of sequence, so you can apply what you have learned here to strings and tuples
Adding items to a list
Use the append
method to add new items to a list:
>>> list1 = ['spam', 'eggs']
>>> list1.append('bacon')
>>> list1
['spam', 'eggs', 'bacon']
Similarly, use the extend
method to append a list of items to another list:
>>> list1.extend(['spam', 'spam'])
>>> list1
['spam', 'eggs', 'bacon', 'spam', 'spam']
The insert
method allows you to insert an item at a specific position using a list index:
>>> list1.insert(3, 'sausages')
>>> list1
['spam', 'eggs', 'bacon', 'sausages', 'spam', 'spam']
Finally, the slice notation can be used to replace a section of a list with another list:
>>> list1[1:4] = ['spam', 'spam', 'spam']
>>> list1
['spam', 'spam', 'spam', 'spam', 'spam', 'spam']
Removing items from a list
List items can be removed using the del
command and the item’s index:
>>> L = ['Graham', 'Eric', 'Terry', 'John', 'Terry', 'Michael']
>>> del L[-1]
>>> L
['Graham', 'Eric', 'Terry', 'John', 'Terry']
If you don’t know the index of item, you can use the remove
method and refer to the item itself:
L.remove('Terry')
>>> L
['Graham', 'Eric', 'John', 'Terry']
If an item appears multiple times in the list, only the first one is removed.
The slice notation can be used to remove several continuous items at once:
>>> del L[1:3]
>>> L
['Graham', 'Terry']
‘Popping’ items
The pop
method removes an item from a list and at the same time returns it. This is useful to make lists behave like stacks.
Here we take the last item from the stack:
>>> myList = ['parrot', 'ant', 'fish', 'goat', 'cat', 'rabbit', 'frog']
>>> myList.pop()
frog
If we ask to see the list again, we can see that the last item is gone:
>>> myList
['parrot', 'ant', 'fish', 'goat', 'cat', 'rabbit']
The pop
method can also take a index – this allows us to take out an item which is not the last one:
>>> myList.pop(0) # take the first item
'parrot'
>>> myList
['ant', 'fish', 'goat', 'cat', 'rabbit']
Sorting lists
List items can be sorted using the sort
method.
Sorting is straightforward when all items in a list are of the same type.
For example, if all items are strings, the list will be sorted alphabetically:
>>> stringsList = ['parrot', 'ant', 'fish', 'goat', 'cat', 'rabbit', 'frog']
>>> stringsList.sort()
>>> stringsList
['ant', 'cat', 'fish', 'frog', 'goat', 'parrot', 'rabbit']
If all items are numbers, they will be sorted numerically in ascending order:
>>> numbersList = [7, 3.1416, 13, -273.15, 2.718, 0, 356.25]
>>> numbersList.sort()
>>> numbersList
[-273.15, 0, 2.718, 3.1416, 7, 13, 356.25]
Reversing a list
The reverse
method can be used to revert the order of the items in a list:
>>> aList = ['one', 'two', 'three', 'four', 'five']
>>> aList.reverse()
>>> aList
['five', 'four', 'three', 'two', 'one']
The sort
method also has a reverse
keyword to invert the default sorting order from ascending to descending:
# sort list items in reverse alphabetical order
>>> aList.sort(reverse=True)
>>> aList
['two', 'three', 'one', 'four', 'five']
Sorting lists with mixed object types
If a list contains different types of objects, we need to define a parameter for comparison. A straight sort with different object types is like comparing apples to oranges, and will not work in Python 3:
>>> mixedList = ['z', 'a', 'abcdefg', 100, 2.4, True, [], None]
>>> mixedList.sort()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: '<' not supported between instances of 'int' and 'str'
How does a number compare to a string? How do numbers and strings compare to lists, boolean values, or to None
? There are different ways to answer these questions depending on the context and on the desired result.
Sorting mixed lists was supported in Python 2, but only thanks to many assumptions about comparisons between types. Python 3 requires us to be explicit about the comparison criteria used for sorting.
The example script shows how to sort a list containing different data types using a key function:
# create a flat list containing strings and numbers
myList = ['Graham', 'Eric', 'Terry', 'John', 'Terry', 'Michael']
myList += ['parrot', 'ant', 'fish', 'goat', 'cat', 'rabbit', 'frog']
myList += [7, 3.1416, 13, -273.15, 2.718, 0, 356.25]
myList += ['3M', '7UP', '7-Eleven']
# define a key function
def sorter(item):
'''Convert a list item into a key for sorting.'''
return str(item).lower()
# sort the list using the key function
myList.sort(key=sorter)
print(myList)
[-273.15, 0, 13, 2.718, 3.1416, 356.25, '3M', 7, '7-Eleven', '7UP', 'ant', 'cat', 'Eric', 'fish', 'frog', 'goat', 'Graham', 'John', 'Michael', 'parrot', 'rabbit', 'Terry', 'Terry']
Sorting lists of values with itemgetter
One of the many uses for lists is storing groups of values. As an example, let’s imagine that we have some very basic information about a group of people as a list of values: a tuple with first name, last name and birth year:
persons = [
# first name, last name, birth year
('Graham', 'Chapman', 1941),
('Eric', 'Idle', 1943),
('Terry', 'Gilliam', 1940),
('Terry', 'Jones', 1942),
('John', 'Cleese', 1939),
('Michael', 'Palin', 1943),
]
Using what we’ve learned in the previous section, we could write separate key functions to sort this list based on different index values:
def lastNameSorter(item):
return item[1]
def birthYearSorter(item):
return item[2]
persons.sort(key=lastNameSorter) # option: key=birthYearSorter
print(persons)
[('Graham', 'Chapman', 1941), ('John', 'Cleese', 1939), ('Terry', 'Gilliam', 1940), ('Eric', 'Idle', 1943), ('Terry', 'Jones', 1942), ('Michael', 'Palin', 1943)]
Notice how the functions repeat a ‘get item’ pattern. This is so common that Python provides a convenience itemgetter
function in the operator
module (we’ll learn more about modules later):
from operator import itemgetter
persons.sort(key=itemgetter(2)) # sort by year
print(persons)
[('John', 'Cleese', 1939), ('Terry', 'Gilliam', 1940), ('Graham', 'Chapman', 1941), ('Terry', 'Jones', 1942), ('Eric', 'Idle', 1943), ('Michael', 'Palin', 1943)]
Using itemgetter
it is also possible to define multiple levels of sorting. For example, sorting by first name (1st item) and last name (2nd item):
persons.sort(key=itemgetter(0, 1))
print(persons)
[('Eric', 'Idle', 1943), ('Graham', 'Chapman', 1941), ('John', 'Cleese', 1939), ('Michael', 'Palin', 1943), ('Terry', 'Gilliam', 1940), ('Terry', 'Jones', 1942)]
Using sorted() and reversed()
In addition to the list.sort
method, Python also offers a sorted()
built-in function which builds a new sorted list from a collection (not just a list). Using sorted(list)
is often more convenient than using list.sort()
.
Here’s an example of sorted()
in use. Notice that the original list is not modified:
>>> flags = ['Foxtrot', 'Bravo', 'Whisky', 'Tango', 'Charlie', 'Echo']
>>> sorted(flags)
['Bravo', 'Charlie', 'Echo', 'Foxtrot', 'Tango', 'Whisky']
>>> flags
['Foxtrot', 'Bravo', 'Whisky', 'Tango', 'Charlie', 'Echo']
The reversed()
built-in function works similarly, but returns an iterator
object instead of a new list.
Both sorted()
and reversed()
are often used to loop over a list of items:
>>> for flag in reversed(flags):
... flag
'Echo'
'Charlie'
'Tango'
'Whisky'
'Bravo'
'Foxtrot'
Creating number sequences
Sequential lists of numbers can be created dynamically using the range
built-in function.
Here’s how we create a list of numbers, starting at 0
and ending before 10
:
>>> list(range(10))
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
In Python 2,
range
returns a list. In Python 3, it returns an iterator object – which we can convert into a list using thelist()
built-in function.
We can start a sequence at a different number by using range
with two arguments:
>>> list(range(5, 10))
[5, 6, 7, 8, 9]
Finally, we can use a third argument to specify an interval between the numbers:
>>> list(range(1, 19, 3))
[1, 4, 7, 10, 13, 16]