So far, we have seen one sequence data type, which is the string data type. Python has 6 additional built-in sequence data type. In this and the upcoming posts, we will be discussing 3 of them which are the lists, tuple and range and see their functions. In this post, we will focus on the list only
let’s see how we can use a built-in function to a sequence data type to make our code more readable.
we will use the example of the valid IP address checker from the previous post, this time instead of having a counter of the dot character we can use a built-in operator that does the same.
ip_address = input("Please enter an IP address: ")
Please enter an IP address: 127.0.0.1
dot_count = ip_address.count(".")
print("We have {} dots in this ip address".format(dot_count))
We have 3 dots in this ip address
Count function returns the number of dots found in the ip_address variable. This function has done all the work of traversing the string, count one by one all the dot characters found and stored the count in the dot_count variable. This is a concise and readable way to write code.
List
We have been introduced to list in the previous posts. Let’s explain it in details; a list is a collection of objects like variables, functions and classes placed in a container. A list has many functions that act upon the elements of a list.
Remember, in Python, everything you write is an object and think of a list as a container of any object. Since a list can contain a string which is by itself a sequence data type this means that a list can also contain other lists, in other words, we can have a container of containers.
let’s illustrate this
burundi_provinces = ["Karuzi","Rutana","Bururi","Makamba","Ruyigi"]
for province in burundi_provinces:
print("Now we are in {}".format(province))
Now we are in Karuzi
Now we are in Rutana
Now we are in Bururi
Now we are in Makamba
Now we are in Ruyigi
We have a sequence of provinces found in Burundi and are stored in a list. The for loop traverses the list and print each element in the list one by one.
Now let’s see when we have a list of lists.
world_countries = [["Angola","DRC","Burundi","Rwanda"],["Spain","Italy","France","UK"],["China","India","Korea"]]
We have a list that contains different countries around the world. These countries are grouped in another list depending on which continent they belong to
for continent in world_countries:
print(continent)
['Angola', 'DRC', 'Burundi', 'Rwanda']
['Spain', 'Italy', 'France', 'UK']
['China', 'India', 'Korea']
looping through the list world_countries, all the lists found will be printed.
We can print the countries one by one using a nested for loop and separate the countries that belong to the same continent with space.
for continent in world_countries:
for country in continent:
print(country)
print()
Angola
DRC
Burundi
Rwanda
Spain
Italy
France
UK
China
India
Korea
we can concatenate two lists together using the addition operator.
even = [2,4,6,8]
odd = [1,3,5,7]
numbers = even + odd
print(numbers)
[2, 4, 6, 8, 1, 3, 5, 7]
List Functions
The same way we have the format function for the string data type, we have different functions for the list data type as well.
Sort function
The sort function will sort a list in numerical or alphabetical order.
numbers.sort()
print(numbers)
[1, 2, 3, 4, 5, 6, 7, 8]
print(numbers.sort())
None
sort( ) function does not create a new list; it acts on the current list permanently. Therefore, it will return None. These kinds of functions are called in-place functions.
There is another function that sorts a list, but instead of returning None, it will create a new sorted list and keep the original list untouched.
numbers_2 = [99,22,1,3,77,3,5,23,51,35,133]
ordered_list = sorted(numbers_2)
print(ordered_list)
print(numbers_2)
[1, 3, 3, 5, 22, 23, 35, 51, 77, 99, 133]
[99, 22, 1, 3, 77, 3, 5, 23, 51, 35, 133]
sorted( ) function will sort the list, but the difference between the sort and the sorted function is that sorted function will create a new list that can be stored in a variable or directly printed. The original list(numbers_2 in this example) will remain unchanged.
We can compare the two lists using the two type of sorting and verify if they are equal.
numbers_2.sort()
if ordered_list == numbers_2:
print("They are equal")
else:
print("They are not equal")
They are equal
Append function
we add an element at the end of a list using the append function.
burundi_provinces = ["Karuzi","Rutana","Bururi","Makamba","Ruyigi"]
burundi_provinces.append("Cibitoke")
for province in burundi_provinces:
print("Now we are in {}".format(province))
Now we are in Karuzi
Now we are in Rutana
Now we are in Bururi
Now we are in Makamba
Now we are in Ruyigi
Now we are in Cibitoke
“Cibitoke” was added at the end of the list, which means that when we loop through the list “Cibitoke” shall be printed at the end.
Insert function
We have seen that the append function add an element at the end of a list, but what if we don’t want the element to be added not at the end but instead somewhere else in the list. That is when the Insert function comes in handy. Insert is like the append function, but the only difference is that we can insert an element at a specific index of our choice in the list.
burundi_provinces.insert(0,"Makamba")
for province in burundi_provinces:
print("Now we are in {}".format(province))
Now we are in Makamba
Now we are in Karuzi
Now we are in Rutana
Now we are in Bururi
Now we are in Makamba
Now we are in Ruyigi
Now we are in Cibitoke
“Makamba” has been added to the list at the beginning of the list because of the first parameter (input in function) in the insert function was 0, which corresponds to the first index in a list.
Now let’s say we want to add a new element to the list, this time the element will be placed between “Rutana” which is at index 2 and “Bururi” which is at index 3.
burundi_provinces.insert(3,"Cankuzo")
for province in burundi_provinces:
print("Now we are in {}".format(province))
Now we are in Makamba
Now we are in Karuzi
Now we are in Rutana
Now we are in Cankuzo
Now we are in Bururi
Now we are in Makamba
Now we are in Ruyigi
Now we are in Cibitoke
“Cankuzo” has taken the place of “Bururi” and “Bururi” has been shifted to index 4.
extend function
As we have already seen, append and insert add a new element to the list. But we can also add a list to a list and have a container of containers.
northern_provinces = ["Kirundo","Ngozi","Kayanza"]
burundi_provinces.insert(3,northern_provinces)
for province in burundi_provinces:
print("Now we are in {}".format(province))
Now we are in Makamba
Now we are in Karuzi
Now we are in Rutana
Now we are in ['Kirundo', 'Ngozi', 'Kayanza']
Now we are in Cankuzo
Now we are in Bururi
Now we are in Makamba
Now we are in Ruyigi
Now we are in Cibitoke
print(burundi_provinces)
['Makamba', 'Karuzi', 'Rutana', ['Kirundo', 'Ngozi', 'Kayanza'], 'Cankuzo', 'Bururi', 'Makamba', 'Ruyigi', 'Cibitoke']
We can see that the list of the northern provinces has been added to burundi_provinces. However, now what if instead for adding the list, there was a merge between the two lists into one.
northern_provinces = ["Kirundo","Ngozi","Kayanza"]
burundi_provinces.extend(northern_provinces)
for province in burundi_provinces:
print("Now we are in {}".format(province))
Now we are in Makamba
Now we are in Karuzi
Now we are in Rutana
Now we are in Cankuzo
Now we are in Bururi
Now we are in Makamba
Now we are in Ruyigi
Now we are in Cibitoke
Now we are in Kirundo
Now we are in Ngozi
Now we are in Kayanza
print(burundi_provinces)
['Makamba', 'Karuzi', 'Rutana', 'Cankuzo', 'Bururi', 'Makamba', 'Ruyigi', 'Cibitoke', 'Kirundo', 'Ngozi', 'Kayanza']
For this round, we have merged the elements from northern_provinces into burundi_provinces using the extend function.
delete keyword
Now that we have seen how to add an element to a list let’s how we can delete it from a list.
let’s say we want to remove “Rutana” from the list which is at index 2
del burundi_provinces[2]
print(burundi_provinces)
['Makamba', 'Karuzi', 'Cankuzo', 'Bururi', 'Makamba', 'Ruyigi', 'Cibitoke', 'Kirundo', 'Ngozi', 'Kayanza']
“Rutana” has been removed from the list using the del keyword which stands for delete followed by burundi_province[2] which will return “Rutana” since it is the element at that specific index and delete it.
remove function
Sometimes we might have an occurrence of element multiple times in a list. To delete the first occurrence of that element, we use the remove function.
let’s append “Karuzi” again in the list.
burundi_provinces.append("Karuzi")
print(burundi_provinces)
['Makamba', 'Karuzi', 'Cankuzo', 'Bururi', 'Makamba', 'Ruyigi', 'Cibitoke', 'Kirundo', 'Ngozi', 'Kayanza', 'Karuzi']
“Karuzi” is at index 1 and index 10, then remove function will delete the first occurrence of “Karuzi” in the list.
burundi_provinces.remove("Karuzi")
print(burundi_provinces)
['Makamba', 'Cankuzo', 'Bururi', 'Makamba', 'Ruyigi', 'Cibitoke', 'Kirundo', 'Ngozi', 'Kayanza', 'Karuzi']
Now we can see that Karuzi at index 1 has been removed, and if we execute the remove function again with “Karuzi” as the parameter, it will search in the list from left to right and delete any occurrence of the element in the list.
pop function
the pop function takes as a parameter the index of the element to delete and return the deleted element.
province_deleted = burundi_provinces.pop(4)
print(province_deleted)
Ruyigi
print(burundi_provinces)
['Makamba', 'Cankuzo', 'Bururi', 'Makamba', 'Cibitoke', 'Kirundo', 'Ngozi', 'Kayanza', 'Karuzi']
The element at index 4, which is “Ruyigi”, has been deleted from the list, returned and stored in the province_deleted variable that we can print.
We could also print it straight away after deleting and returning the element.
print(burundi_provinces.pop(5))
Kirundo
“Kirundo” was deleted from the list and printed.
List features
We can initialize an empty in two different ways. The purpose of initializing an empty list is to contain elements that we don’t know initially.
list_1 = []
list_2 = list()
print("list 1 {}".format(list_1))
print("list 2 {}".format(list_2))
list 1 []
list 2 []
let’s compare them and see if they are equal.
if list_1 == list_2:
print("They are equal")
else:
print("They are not equal")
They are equal
Yep! they are equal
We can either declare a list using [ ] or using list( ) which is called a constructor. A constructor means that we are initializing a list object in memory. We will go in details about constructor when we will learn about classes.
Now let’s check if the lists occupy the same spot in memory.
if list_1 is list_2:
print("They are located at the same place in memory")
else:
print("They are not located at the same place in memory")
They are not located at the same place in memory.
Well, using the “is” keyword, we can see that the two lists are stored into two different places in the computer memory.
So now the question is when to use the constructor form or the bracket form. Well, choose any form you feel comfortable with since both forms do precisely the same thing.
However, there is one advantage of using the constructor form. This form helps us to traverse and print any sequential data type (also called iterable) without using a loop statement like this
print(list("This will print all the characters one by one"))
['T', 'h', 'i', 's', ' ', 'w', 'i', 'l', 'l', ' ', 'p', 'r', 'i', 'n', 't', ' ', 'a', 'l', 'l', ' ', 't', 'h', 'e', ' ', 'c', 'h', 'a', 'r', 'a', 'c', 't', 'e', 'r', 's', ' ', 'o', 'n', 'e', ' ', 'b', 'y', ' ', 'o', 'n', 'e']
Think of this notation as casting a string data type into a list data type.
Let’s see another example.
random_num = [33,17,44,6,244,60,55,23,44,13,22,66]
random_num_2= random_num
random_num_2.sort(reverse=True)
print(random_num_2)
print(random_num)
[244, 66, 60, 55, 44, 44, 33, 23, 22, 17, 13, 6]
[244, 66, 60, 55, 44, 44, 33, 23, 22, 17, 13, 6]
Surprised? Huh? Let me explain what is happening here, we have assigned random_num to random_num_2, and then we have sorted random_num_2 in a reversed order by using reverse=True as a parameter in the sort function. Now comes the confusing part, when we print we print the random_num_2 we can see that the list is now reversed as expected, but when we print random_num we also found out that it is also reversed? But why?
well, the answer is that random_num and random_num_2 are pointing to the same list in computer memory, so any function that is applied to the list affects random_num and random_num_2 since they refer to the same object.
Let’s test again using the “is” keyword to see they refer to the same list in memory.
if random_num is random_num_2:
print("The two variables refer to the same objects in memory")
else:
print("The two variables do not refer to the same objects in memory")
The two variables refer to the same objects in memory.
Now lets test again the two lists but this time we will assign random_num_2 using a constructor.
random_num_2 = list(random_num)
print(random_num_2)
[244, 66, 60, 55, 44, 44, 33, 23, 22, 17, 13, 6]
if random_num is random_num_2:
print("The two variables refer to the same objects in memory")
else:
print("The two variables do not refer to the same objects in memory")
The two variables do not refer to the same objects in memory.
Even though the two lists have the same elements arranged in the same reversed order, the two lists don’t refer to the same list in memory. random_num_2 points to its list and random_num points to another one.
if random_num == random_num_2:
print("The two variables have the same elements and arranged in the same order")
else:
print("The two variables don't have the same elements and are not arranged in the same order")
The two variables have the same elements and arranged in the same order
The same thing will happen when using the sorted function.
random_num_2 = sorted(random_num,reverse=True)
if random_num is random_num_2:
print("The two variables refer to the same objects in memory")
else:
print("The two variables do not refer to the same objects in memory")
The two variables do not refer to the same objects in memory.
if random_num == random_num_2:
print("The two variables have the same elements and arranged in the same order")
else:
print("The two variables don't have the same elements and are not arranged in the same order")
The two variables have the same elements and arranged in the same order
No surprise here since the two lists have the same elements arranged in the same manner.
Challenge
For this challenge, we will have a list that contains lists of ingredients. These lists of ingredients will be added to the list then print all the ingredients that don’t contain a specific unwanted ingredient. For example, let’s say that we don’t want “nuts” as an ingredient; the program shall print all the list elements that do not have “nuts” in it. While printing, we shall have a count of each element.
Now go ahead and try this challenge on your own and only after you have tried, come back and compare your solution with mine.
Challenge solution
meals = []
meals.append(["beans","egg","nuts","rice"])
meals.append(["cabbage","bread","banana","carots"])
meals.append(["bacon","beaf","steak","nuts"])
meals.append(["tomatos","burger","mustard","nuts"])
meals.append(["fries","chicken","nuts","avocado"])
meals.append(["meat","sukuma","ugali"])
for meal in meals:
if "nuts" not in meal:
for index,element in enumerate(meal,1):
print("element {} is {}".format(index,element))
print()
element 1 is cabbage
element 2 is bread
element 3 is banana
element 4 is carots
element 1 is meat
element 2 is sukuma
element 3 is ugali
We first append to the list all the ingredients and loop through the elements of each list and check if any the element is “nuts” if there is this list will be ignored until we get a list that does not contain “nuts”.
After this finding, we will loop through the list and enumerate all the elements using the enumerate function. There the second parameter in the enumerate function; this parameter corresponds to the starting count. By default, this parameter is not written and is set to 0; we can overwrite this by placing any number which will be the starting point of the count. There is an empty space after all the elements in the list are done printing.
Conclusion
A list is a clean way of storing data in a container that allow us to iterate over on its elements and perform a useful operation on it like adding and removing new elements. We will be using lists a lot. In the upcoming post, we will discuss tuples and ranges.
Find the jupyter notebook version of this post on my GitHub profile here.
Thank you for reading this tutorial. I hope you have learned one or two things. If you like this post, please subscribe to stay updated with new posts, and if you have a thought or a question, I would love to hear it by commenting below. Remember keep learning!