Lists

A list is a tool for storing a sequence of values. The individual values contained within a list are called the elements or items of the list.

To define a list in Python, we write the elements of the list between a pair of square braces, separated by commas.In the cell below, we create a list containing strings representing the names of each of the eight planets in our solar system. We will store the list in the variable planets.

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

List objects have a data type, just like every other object in Python. In the following cell, we check the type of planets.

type(planets)
list

We can also print lists.

print(planets)
['Mercury', 'Venus', 'Earth', 'Mars', 'Jupiter', 'Saturn', 'Uranus', 'Neptune']

Accessing List Elements

Elements in a list are assigned an order when the list is defined, and each element being assigned a numerical position called an index. The first element is assigned an index of 0, the second element is assigned an index of 1, the third element is assigned an index of 2, and so on.

Assume you have a list called my_list, and you wish to access an element whose index is stored in a variable i. This can by done using the following code: my_list[i].

# Print the 1st element of planets
print(planets[0])
Mercury
# Print the 3rd element of planets
print(planets[2])
Earth
# Print the 8th element of planets
print(planets[7])
Neptune

We will get an error if we try to access a list element that does not exist.

print(planets[8])
---------------------------------------------------------------------------
IndexError                                Traceback (most recent call last)
<ipython-input-7-c5c892610201> in <module>
----> 1 print(planets[8])

IndexError: list index out of range

We can also access elements of a list by counting from the end of the list. This is accomplished through the use of negative indices. The last element in the list is a index -1, the second to last is at index -2, and so on.

# Print the last element of planets.
print(planets[-1])
# Print the 3rd from last element of planets. 
print(planets[-3])

In the cell below, write two lines of code that each print out “Mars”. Use a positive index in the first line and a negative index in the second line.

print(planets[3])
print(planets[-5])

Types of List Elements

While a list object is of data type list, the individual elements of a list will each have their own data types. For example, the elements of the elements of planets list we defined previously are all of type str.

print(type(planets))
print(type(planets[4]))

It is possible to create lists that contain other data types. The following list contains elements of type int.

pi_digits = [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5]
print(pi_digits[5])

This list contains elements of type bool.

bool_list = [False, True, True, False, True]
print(bool_list[3])

It is even possible for a single list to contains elements of several different data types.

varied_list = [False, "one", 2, 3.0]
print(type(varied_list))
print(type(varied_list[0]))
print(type(varied_list[1]))
print(type(varied_list[2]))
print(type(varied_list[3]))

In fact, it is even possible for lists to contain other lists! We will further discuss this concept soon.

Slicing Lists

Occasionally, we will need to need to work with a portion of a list, rather than the entire list. Slicing is a method of creating a sublist of consecutive elements drawn from another list. Assume that myList is a Python list, and let i and j be integers.

  • myList[i:j] will generate a sublist of myList that begins with the element at index i and contains all elements up to but not including the element at index j.

  • myList[i:] will generate a sublist of myList that begins with the element at index i and contains all later elements.

  • myList[:j] will generate a sublist of myList that contains all elements up to but not including the element at index j.

# Simple Slicing Example
simpleList = [0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20]

print(simpleList[3:7])
print(simpleList[5:])
print(simpleList[:8])

We can also use negative indices when specifying a slice of a list.

# Print the last 6 elements of simpleList
print(simpleList[-6:])
# Print all but the first two and last two elements of simpleList
print(simpleList[2:-2])

Example: Quarterly Sales

CompCo is an company that manufactures laptop computers. The list sales below provides CompCo’s total monthly sales for each month of 2016, measured in US dollars. The results are listed in order of month.

sales = [52353, 43724, 32191, 34914, 44671, 37139, 49341, 
         57139, 55104, 45193, 52167, 61294]

CompCo needs to calculate their quarterly sales for each quarter in 2016.

Define four new variables Q1, Q2, Q3, and Q4 in the next cell.

  • Q1 contains the total sales for Quarter 1 (January, February, March).

  • Q2 contains the total sales for Quarter 2 (April, May, June).

  • Q3 contains the total sales for Quarter 3 (July, August, September).

  • Q4 contains the total sales for Quarter 4 (October, November, December).

Use a combination of slicing and the sum() function.

Q1 = sum(sales[0:3])
Q2 = sum(sales[3:6])
Q3 = sum(sales[6:9])
Q4 = sum(sales[9:])

Print the variables Q1, Q2, Q3, and Q4.

print(Q1)
print(Q2)
print(Q3)
print(Q4)

Altering Lists

The elements of a list can be altered after the list has been created. We can make changes to the elements of a list in the following ways:

  1. Updating elements We can replace the value stored at a particular index with any other value.

  2. Adding elements We can insert new elements into a list at any position that we choose.

  3. Removing elements We can delete any element from a list.

We illustrated each of these concepts below.

# Define the list Fruit.
Fruit = ['apple', 'ornge', 'lemon', 'grap', 'peach']
print(Fruit)

Modifying elements of a list

Two of the elements in our list were misspelled. We will replace these elements with correctly spelled entries.

Fruit[1] = 'orange'
Fruit[3] = 'grape'
print(Fruit)

Inserting elements into a list

The insert() list method allows us to add elements to a list at a specified position. Any elements whose previous indices were greater than or equal to the index of the newly inserted element will be pushed back one position.

# Insert plum as the second element of the list.
Fruit.insert(1, 'plum')
print(Fruit)
# Insert lime as the fifth element of the list.
Fruit.insert(4, 'lime')
print(Fruit)

Appending elements to a list

The append() method is similar to insert(), except that no position is specified. Appended elements are always added to the end of the list.

# Add strawberry and raspberry to the end of the Fruit list.
Fruit.append('strawberry')
Fruit.append('raspberry')
print(Fruit)

Deleting list elements by index

We may use the del keyword to delete the element of a list at a certain index.

# Delete the third element of the Fruit list.
del Fruit[2]
print(Fruit)

Keep in mind that once an element is deleted (or inserted), all later elements will have their indices updated.

# Delete the first two elements of the Fruit list.
del Fruit[0]
del Fruit[0]
print(Fruit)

Deleting list elements by value

The remove() method will search through a list and remove the first element that matches the supplied argument. If there are multiple elements equal to the given argument, only the one with the lowest index will be deleted.

# Remove the first instance of peach from the list.
Fruit.remove('peach')
print(Fruit)
# Add a second lime element to the end of the list.
Fruit.append('lime')
print(Fruit)
# Remove the first instance of lime from the list. 
Fruit.remove('lime')
print(Fruit)

Example: Altering Lists

A list of integers is defined in the next cell. Perform the requested tasks on this list.

intList = [3, 11, 45, 14, 47, 18, 42, 41, 20, 13, 33, 6]

Update the element whose value is 18 to have a value of 28. Print intList.

intList[5] = 28
print(intList)

Insert an element with a value of 42 between the elements whose values are 20 and 13. Print intList.

intList.insert(9, 42)
print(intList)

Use the append() method to add an element with a value of 34 to the end of the list. Print intList.

intList.append(34)
print(intList)

Use the remove() method to delete the first occurence of 42 in the list. Print intList.

intList.remove(42)
print(intList)

Use the del keyword to delete the first three elements of intList. Print intList.

del intList[0]
del intList[0]
del intList[0]
print(intList)

The output of the last cell should be: [14, 47, 28, 41, 20, 42, 13, 33, 6, 34]

List Concatenation and Replication

As with strings, we can use the operators + and * to concatenate and replicate lists.

  • When + appears between two lists, the expression will be evaluated as a new list that contains the elements from both lists. The elements in the list on the left of + will appear first, and the elements on the right will appear last.

  • When * appears between a list and an integer, the expression will be evaluated as a new list that consists of several copies of the original list concatenated together. The number of copies is set by the integer.

letter_list = ['A', 'B', 'C']
number_list = [1, 2, 3]

print(letter_list + number_list)
print(number_list * 4)

List Functions

Python has several functions that can take lists as inputs. We will present four such functions here.

  • len() returns the number of items in the list.

  • sum() returns the sum of the elements in a list. This only works on numerical lists.

  • max() returns the largest item in the list.

  • min() returns the smallest item in the list.

We will illustrate the use of these functions using the two lists below.

names = ['beth', 'drew', 'fred', 'chad', 'anna', 'emma']
sales = [126, 81, 135, 114, 163, 92]
# Find the length of the lists.
print(len(names))
print(len(sales))
# Sum the sales list.
print(sum(sales))
# Find min and max of names list.
print(min(names))
print(max(names))
# Find min and max of sales list.
print(min(sales))
print(max(sales))

Sorting Lists

Python provides us with a few tools for sorting and reordering the elements of a list. In this section, we will discuss the following functions: the sorted() function, the sort() method, and the reverse() method.

sorted() Function

We can use sorted() to obtain a sorted version of the list. Note that this does not alter the order of the original list. It creates list which contains the same elements of the original list, but in sorted order. We can then store this new list in a variable, print it, or provide it to another function.

listA = [6, 9, 1, 4, 7, 3, 6, 4, 5, 2]
listA_asc = sorted(listA)

print('Sorted List:  ', listA_asc)
print('Original List:', listA)

The sorted() function sorts items in ascending order by default. We can change this behavior by setting an optional parameter named reverse. This parameter accepts a Boolean value, and is set equal to False by default. If reverse is set to True, then the list will be sorted in descending order.

listA_desc = sorted(listA, reverse=True)

print('Sorted List:  ', listA_desc)
print('Original List:', listA)

The sort() Method

As mentioned above, the sorted() function does not alter the order of the original list, but instead creates a new list. There are occasions when we only intend to work with a sorted version of the list, and would thus perfer to perform the sort on the original list itself, rather than creating a new list. One option would be to use sorted(), and then store the results back into the variable that held the original list. However, a simpler approach would be to use the sort() list method.

The sort() method for lists will sort the elements of a list in ascending order. The method does not create any new lists, but instead rearranges the elements of the orignal list. This is referred to as “in place” sorting.

listB = [6, 9, 1, 4, 7, 3, 6, 4, 5, 2]
listB.sort()
print(listB)

Like the sorted() function, the sort() method has an optional reverse parameter that can be used to sort the list in descending order.

listC = [6, 9, 1, 4, 7, 3, 6, 4, 5, 2]
listC.sort(reverse=True)
print(listC)

sorted() vs sort()

The fact that sort() performs an in-place sort while sorted() creates a new list illustrates a difference between methods and lists. Methods can have permission to directly alter the value of the object that they are working on, while other types of function generally do not.

You might be asking how to decide which of these sorting functions to use if you need to sort a list. The answer essentially boils down to whether or not you need to preserve the original list, or if you only intend to ever work with the sorted version of the list. If you need need to preserve the original order, then you should sort using sorted(). However, if don’t need the original ordering and will only work with the sorted version of the list, then you should use sort().

The reverse() Method

Lists also have a reverse() method when reverses the order of a list. This re-ordering is performed on the elements of the original list, and does not create any new lists. That is, it is done “in place”.

listD = [6, 9, 1, 4, 7, 3, 6, 4, 5, 2]
listD.reverse()
print(listD)

Note that reverse() does not sort the list in descending order. It simply reverses the current order of the list. We saw previously that we can obtain an in-place sort of a list in descending order by specifying reverse=True when using the sort() method. We could also call the sort() method on a list to first sort the list in ascending order, and then call the reverse() method on the list to put the list into descending order. However, this would require two lines of code. We illustrate this technique in the cell below.

listE = [6, 9, 1, 4, 7, 3, 6, 4, 5, 2]
listE.sort()
listE.reverse()
print(listE)

Finding Index of List Elements

Lists have an index() method that accepts a single parameter. The method will return the index of the first occurrence of the supplied value within the list. If the value does not appear in the list, the method will produce an error.

The cell below creates a randomly generate list of 30 elements. Run this cell as is.

import random
random.seed(1)
rand_list = random.choices(range(0,50), k=30)
print(rand_list)

The value 1 appears multiple times in this list. The code in the cell below will return the index of the first occurrence of 1.

rand_list.index(1)

The value 2 does not appear in the list. The code below will result in an error.

rand_list.index(2)

Copying Lists

Assume that var1 is a variables of type int, float, str, or bool. We have seen before that if we create a new variable var2 and set its initial value to be equal to that of var1, then var2 will initially contain the same value as var1, but will be its own distinct variable whose value can be changed independent of var1. This is illustrated in the following two cells.

var1 = 37
var2 = var1 
print(var1)
print(var2)
var2 = "blah"
print(var1)
print(var2)

The situation is different for lists, however. If we have a list called list1 and we set list2 to be equal to list1, then list1 and list2 will be two different names of the same list. Any changes made to list1 will also effect list2 and vice versa.

list1 = [3, 8, 2]
list2 = list1
print(list1)
print(list2)
list2.append(37)
print(list1)
print(list2)

What if we want to actually create a new, entirely separate, copy of an already existing list? It turns out that Python provides two ways of doing a such.

  1. We may use the copy() method of the list that we wish to duplicate.

  2. We can return a copy of a list by using slicing.

Let’s see first see how to duplicate a list using the copy() method.

dup1 = list1.copy()
print(list1)
print(dup1)
dup1.append(42)
print(list1)
print(dup1)

We will now see how to duplicate a list by using slicing.

dup2 = list1[:]
print(list1)
print(dup2)
dup2.remove(8)
print(list1)
print(dup2)

Example: Copying and Sorting Lists

A list called Avengers is provided in the cell below. Add code to accomplish the following tasks:

  1. Create two new copies of the list, one called Avengers_Asc and one called Avengers_Desc.

  2. Sort Avengers_Asc in ascending alphabetical order.

  3. Sort Avengers_Desc in descending alphabetical order.

  4. Print all three lists.

Avengers = ['Capt. America', 'Black Widow', 'Iron Man', 'Hulk', 'Thor', 'Hawkeye']

Avengers_Asc = Avengers.copy()
Avengers_Desc = Avengers.copy()

Avengers_Asc.sort()
Avengers_Desc.sort(reverse=True)

print(Avengers)
print(Avengers_Asc)
print(Avengers_Desc)
Avengers_Asc = sorted(Avengers)
Avengers_Desc = sorted(Avengers)
Avengers_Desc.reverse()

print(Avengers)
print(Avengers_Asc)
print(Avengers_Desc)

Working with Data Stored in Parallel Lists

Occasionally, we will need to use multiple lists to store different types of data collected for several people or objects. When doing so, the lists are typically created so that entries of different lists at the same position provide different pieces of information all relating to the same entity.

As an example, the cell below creates a list names that contains the names of 10 people as well as a list called ages that stores the ages of the same 10 people. The two lists correspond in the sense that for each index i, the age of the person with name name[i] is equal to age[i].

names = ['Ivan', 'Dawn', 'Eric', 'Fred', 'Anna', 'Beth', 'Chad', 'Judy', 'Gary', 'Hana']
ages = [19, 61, 56, 26, 40, 38, 49, 57, 17, 13]

When we store data in “parallel” lists, Python will not be aware that the lists are meant to be related. The index() method can be useful for working with lists of this type.

Assume that we wish to determine the names and ages of the youngest and oldest people in these lists. We could certainly get the answer by manually inspecting the contents of the list, but that would be tedious to do if the lists were very long. The index() method can be used to develop a programmatic solution to this task.

In the cell below, we will write code to obtain and print the following information:

  • The name, age, and index for the youngest individual whose information is stored in the lists.

  • The name, age, and index for the oldest individual whose information is stored in the lists.

# Obtain information about youngest person.
min_age = min(ages)
idx_min = ages.index(min_age)
min_name = names[idx_min]

# Obtain information about oldest person.
max_age = max(ages)
idx_max = ages.index(max_age)
max_name = names[idx_max]

# Print results.
print('The youngest person is ', min_name, '. Their age is ', min_age, 
      '. Their information is stored at index ', idx_min, '.', sep='')

print('The oldest person is ', max_name, '. Their age is ', max_age, 
      '. Their information is stored at index ', idx_max, '.', sep='')

Nested Lists

It is possible for the elements of a list to be lists themselves. Let’s consider a simple example.

metaList = [ 
    [4, 2], 
    ['a', 'b', 'c', 'd'], 
    [1.1, 2.2, 3.3] 
]

Notice that metalist is a list that contains three elements, each of which is also a list.

  • metaList[0] is a list of two int values, [4, 2].

  • metaList[1] is a list of four str, ['a', 'b', 'c', 'd'].

  • metaList[2] is a list of three float values, [1.1, 2.2, 3.3].

We can access elements of the inner lists by using two sets of square braces and two indices.

For example, since metaList[1] is the list ['a', 'b', 'c', 'd'], we can access the str 'c' with metaList[1][2].

print(metaList[1][2])

Example: Working with a List of Lists

In the cell below, we have created lists for 9 midwest states. Each state list contains the names of the cities in that state with a population of 100,000 or greater.

MO_list = ['Independence', 'Kansas City', 'Springfield', 'St. Louis']
IL_list = ['Aurora', 'Chicago', 'Joliet', 'Napierville', 'Peoria', 'Rockford', 'Springfield']
AR_list = ['Little Rock']
KS_list = ['Kansas City', 'Olathe', 'Overland Park', 'Topeka', 'Wichita']
IA_list = ['Cedar Rapids', 'Des Moines']
NE_list = ['Lincoln', 'Omaha']
OK_list = ['Norman', 'Oklahoma City', 'Tulsa']
TN_list = ['Chattanooga', 'Clarksville', 'Knoxville', 'Memphis', 'Nashville']
KY_list = ['Lexington', 'Louisville']

We will now create a list that contains each of these 9 lists as its elements.

state_list = [MO_list, IL_list, AR_list, KS_list, IA_list, 
              NE_list, OK_list, TN_list, KY_list]

Without referring directly to any of the 9 original lists, print out a list of the cities in Kansas with a population of 100,000 or greater.

print(state_list[3])

Without referring directly to any of the 9 original lists, print out a list of the cities in Nebraska with a population of 100,000 or greater.

print(state_list[5])

Using only the list cities_100K, print the element 'St. Louis'.

print(state_list[0][3])

Using only the list cities_100K, print the element 'Joliet'.

print(state_list[1][2])