We use variables to store data or the “state” of our program. By assigning values or accessing the values associated with variables, we can “remember” or “write down” information. In most programs, the data is used to help determine which instructions to execute. Depending on the values in our variables, the behavior of a function may change or (as we will see in future weeks), the specific code that is executed may be different.
So far, a variable has only been able to hold a single data item, like a single integer, or boolean, or string. On the other hand, we have also seen that we can think of a string as being a sequence of characters. In this topic, we will look at a data structure called a list that we can use to hold a sequence of any type. We will be able to have sequences of integers, or booleans, or strings, or …
When thinking of a list, it may help to think of waiting in a line to checkout at a store. Everyone is waiting in a sequential order. Just remember, just like string indices start at 0, the first element of list is stored at index 0!
We can create a list literal by putting the values inside [ ] and separated by commas:
["dinosaur", "wolf", "goose"] # creates a list with 3 elements
We can also create an empty list:
[] # creates an empty list with no elements
And we can create a list with repeated entries using the repetition * operator:
[0]*5 # creates a list with 5 elements, all of value 0; equivalent to [0,0,0,0,0]
Typically, we will want to keep track of a list by assign it to a variable; its type is list.
animals:list = ["dinosaur", "wolf", "goose"]
There are a lot of similarities between how we work with strings and how we work with lists. Useful operations on the list are to access an individual value in the list using its position as an index inside [ ]. As with strings, we start counting with 0.
animals:list = ["dinosaur", "wolf", "goose"]
mascot:str = animals[2]
Another common operation is to determine how many values are in a list or its length. Just as with strings, we use the len function for this.
animals:list = ["dinosaur", "wolf", "goose"]
numberAnimals:int = len(animals)
Remember that strings were immutable -- their contents could not be changed.
Lists, on the other hand, can be changed!
We can update a value in the list by using the [ ] syntax, putting the list variable on the lefthand side of the assignment statement, like this:
animals:list = ["dinosaur", "wolf", "goose"]
animals[0] = "turtle"
Now, the animals list evaluates to:
["turtle", "wolf", "goose"]
(Note that you cannot change an individual character in a string like this, though!)
We can also take slices of lists, using the same syntax as we saw with strings. For example, after executing this code:
animals:list = ["dinosaur", "wolf", "goose"]
predators:list = animals[0:2]
predators evaluates to
["dinosaur", "wolf"]
Just like strings, we can join or concatenate two lists using the concatenation + operator. This will return a new list with the elements of the first list followed by the elements of the second list.
For example, after executing this code:
animals:list = ["dinosaur", "wolf", "lion" ]
habitats:list = ["jungle", "forest", "savannah"]
nouns:list = animals + habitats
nouns evaluates to
['dinosaur', 'wolf', 'lion', 'jungle', 'forest', 'savannah']
Like strings, lists in Python are objects and have certain methods they support. Here are a few of the most useful ones!
append
We can add an element to the end of a list using the append method, which requires a single parameter with the value to add.
For example, after executing this code:
animals:list = ["dinosaur", "wolf", "goose"]
animals.append( "turtle" )
animals evaluates to
["dinosaur", "wolf", "goose", "turtle"]
insert
We can insert an element at an arbitrary spot in a list using the insert method, which requires two parameters: the index at which we want to insert the element (where we want it to be) and the value to be inserted.
For example, after executing this code to insert a new element after index 1:
animals:list = ["dinosaur", "wolf", "goose"]
animals.insert( 1, "turtle" )
animals evaluates to
["dinosaur", "turtle", "wolf", "goose"]
Observe that the new element "turtle" ends up at index 1, and all elements following were bumped up a slot.
remove (by value)
We can remove an element from a list using the remove method, which requires a single parameter with the value to removed; all occurrences of that value will be deleted.
For example, after executing this code:
animals:list = ["dinosaur", "wolf", "goose", "wolf"]
animals.remove( "wolf" )
animals evaluates to
["dinosaur", "goose", "turtle"]
pop (by index)
We can extract an element from a list by its position using the pop method, which requires a single parameter with the index of the element to remove. The value at that index will be returned.
For example, after executing this code:
animals:list = ["dinosaur", "wolf", "goose", "turtle"]
bird:str = animals.pop( 2 )
animals evaluates to
["dinosaur", "wolf", "turtle"]
and bird evaluates to
"goose"
sort
It's often useful to have a list in sorted order. Sorting is an entire CS topic in its own right that you would encounter later in a CS curriculum, but in this course we can simply use the built-in method that Python offers. The sort method requires no parameters and modifies the list to have its elements in order (respecting the <= operator).
For example, after executing this code to sort the list:
animals:list = ["dinosaur", "wolf", "goose"]
animals.sort()
animals evaluates to
["dinosaur", "goose", "wolf"]
We can pass an optional parameter to sort in descending order. To pass an optional parameter, we use its name and assign it the value. For example, after executing this code:
animals:list = ["dinosaur", "wolf", "goose"]
animals.sort( reverse=True )
animals evaluates to
["wolf", "goose", "dinosaur"]
We can also customize the comparison to not immediately use the "regular" ordering (associated with <=) by passing the name of a function that is invoked on each element of the list; the resulting value is then substituted in before the "regular" ordering is used.
For example, suppose we wanted to sort the list by the number of vowels in each word:
def numVowels( word:str ) -> int:
""" Given a string, counts and returns the number of vowels in the word. """
# invoke the string object's lower method to make the word lowercase
lowerWord:str = word.lower()
return word.count("a") + word.count("e") + word.count("i") \
+ word.count("o") + word.count("u")
animals:list = ["dinosaur", "wolf", "goose", "kangaroo"]
animals.sort(key=numVowels)
By invoking sort and specifying the optional parameter key to be the function numValues, we end up with animals evaluating to:
['wolf', 'goose', 'dinosaur', 'kangaroo']
Consider the following code block -- can you predict what will be printed? Try running it to see if you are right. Use PythonTutor to help you understand the details.
# create a list with 2 elements and assign it to a variable weather
weather = ["sleet", "rain"]
# print the list to see what's in there
print( f"The weather list holds: {weather}." )
# access the element at index 0 (the first in the list) and store it in a variable
initialWeather = weather[0]
# print it out
print( f"The first weather element {initialWeather}." )
# print how many elements are in the weather list
print( f"The weather list has {len(weather)} elements." )
# update the value to the element at index 0 (the first element)
weather[0] = "sunshine"
# print the list to see what's in there
print( f"After updating the first element, weather now holds: {weather}." )
# add a new value to the end of the list
weather.append( "hail" )
# print the list to see what's in there
print( f"After appending to the list, weather now holds: {weather}." )
# insert a new value into the first spot (index 0)
weather.insert( 0, "snow" )
# print the list to see what's in there
print( f"After inserting into the list, weather now holds: {weather}." )
# sort the list in (ascending) alphabetical order
weather.sort()
# print the (now sorted) list
print( f"After sorting, weather now holds: {weather}." )
Consider the following code block -- can you predict what will be printed? Try running it to see if you are right. Use PythonTutor to help you understand the details.
def lastDigit( num:int ) -> int:
""" Given a number, return its last digit. """
return num%10
# create a list with 4 elements, all value 1
numbers:list = [1]*4
# print the list to see what's in there
print( f"The numbers list initially holds: {numbers}." )
# update the value of index 0 to hold the number 1837
numbers[0] = 1837
# print the list to see what's in there
print( f"After updating the first element, the numbers list holds: {numbers}." )
# append a number to the list
numbers.append( 2022 )
# print the list to see what's in there
print( f"After appending, the numbers list holds: {numbers}." )
# insert a number into the list
numbers.insert(1, 2008)
# print the list to see what's in there
print( f"After inserting, the numbers list holds: {numbers}." )
# remove the element at index 3
numbers.pop( 3 )
# print the list to see what's in there
print( f"After popping, the numbers list holds: {numbers}." )
# create a new list
moreNumbers:list = [29,14,15]
# print the list to see what's in there
print( f"The moreNumbers list holds: {moreNumbers}." )
# combine the two lists into yet another list
evenMoreNumbers:list = numbers + moreNumbers
# print the list to see what's in there
print( f"The evenMoreNumbers list holds: {evenMoreNumbers}." )
# sort the list in descending order by the last digit
evenMoreNumbers.sort( reverse=True, key=lastDigit )
# print the list to see what's in there
print( f"After sorting, the evenMoreNumbers list holds: {evenMoreNumbers}." )