Sequences in Python: Lists

One way to think of a Python list is that it is a tuple in which the components can be modified. They have many properties of an array of the sort one might find in Java or C, in that they can be used as a place to store things and have ran­dom access to them; any element can be read or written. They are often used as one might use an array, but have a greater natural functionality.

Initially a list looks like a tuple, but uses square brackets to delimit it.

listl = [2, 3, 5, 7, 11, 13, 17, 19]  # Prime numbers under 20

list2 = [“Hydrogen”,”Helium”,”Lithium”,”Beryllium”,”Boron”, “Carbon”]

list3 = [“hi”, “ohio”, “salut”]

A list can be empty:

list4 = []

and because they are like tuples and strings, each element in a list has an index, and they begin (as usual) at 0. Lists can be indexed and sliced, as before:

list1[2:4] is [5, 7]

The concatenation is like that of strings, too: list6 = list1 + [23, 31] yields [2, 3, 5, 7, 11, 13, 17, 19, 23, 31]

Negative values index from the end of the string. However, unlike strings and tuples, individual elements can be modified. So

list1[2] = 6

results in listl being [2, 3, 6, 7, 11, 13, 17, 19]. Also,

list3[1:] = “bonjour”

results in list3 taking the value oops; it becomes

[‘hi’, ‘b’,  ‘o’, ‘n’, ‘j’, ‘o’, ‘u’, ‘r’].

That’s because a string is a sequence, too, and this string consists of seven components. Each component of the string becomes a component of the list. If the string “bonjour” is supposed to become a single component of the list, then it needs to be done this way:

list3[1:] = [“bonjour”]

The other components of list3 are sequences, and now so is the new one. However, integers are not sequences, and the assignment

list1[2] = [6,8,9]

results in the value of list2 being

[2, 3,[6, 8, 9], 7, 11, 13, 17, 19]

There is a list within this list; that is, the third component of listl is not an integer, but is a list of integers. That’s legitimate, and works for tuples as well, but may not be what is intended.

Problem: Compute the average (mean) of a list of numbers.

The mean is the sum of all numbers in a collection divided by the number of numbers. If a set of numbers already exists as a list, calculating the mean might involve a loop that sums them followed by a division. For example, assuming that listl = [2, 3, 5, 7, 11, 13, 17, 19]:

mean = 0.0

for i in listl:

mean = mean + i

mean = mean/len(list1)

A list can be used in a loop to define the values that the loop variable i takes on, a similar situation to that of a tuple. A second way to do the same thing would be

mean = 0.0

for i in range(0,len(list1)):

mean = mean + list1[i]

mean = mean/len(list1)

In this case, the loop variable i is an index into the list and not a list element, but the result is the same. Python lists are more powerful than this, and making use of the extensive power of the list simplifies the calculation:

mean = sum(listl) / len(listl)

The built-in function sum calculates and returns the sum of all of the ele­ments in the list. That was the purpose of the loop, so the loop is not needed at all. The functions that work for tuples also work for lists (min, max, len), but some of the power of lists is in the methods it provides.

1. Editing Lists

Editing a list means to change the values within it, usually to reflect a new situation to be handled by the program. The most obvious way to edit a list is to simply assign a new value to one of the components. For example,

list2 = [“Hydrogen”,”Helium”,”Lithium”,”Beryllium”,”Boron”, “Carbon”]

list2[0] = “Nitrogen”

print (list2)

results in the following output:

[‘Nitrogen’, ‘Helium’, ‘Lithium’, ‘Beryllium’, ‘Boron’, ‘Carbon’]

This substitution of a component is not possible with strings or tuples. It is possible to replace a single component with another list:

list2 = [“Hydrogen”,”Helium”,”Lithium”,”Beryllium”, “Boron”,”Carbon”]

list2[0] = [“Hydrogen”, “Nitrogen”]

results in

list2 = [[‘Hydrogen’,’Nitrogen’],’Helium’,’Lithium’, ‘Beryllium’,’Boron’,’Carbon’]

2. Insert

The insert method is not normally what is thought of as an insertion. We use the insert method to place new components within a list. This method places a component at a specified index; that is, the index of the new element will be the one given. To place “Nitrogen” at the beginning of list2, which is index 0,

list2.insert(0, “Nitrogen”)

The first value given to insert, 0 in this case, is the index at which to place the component, and the second value is the thing to be inserted. Inserting “Nitrogen” at the end of the list would be accomplished by

list2.insert(len(list2), “Nitrogen)

However, consider this:

list2.insert(-1, “Nitrogen)

Will this insert “Nitrogen” at the end? No. At the beginning of the statement, the value of list2[-1] is “Carbon.” This is the value at index 5. Therefore, the in­sert of “Nitrogen” will be at index 5, resulting in

[‘Hydrogen’, ‘Helium’, ‘Lithium’, ‘Beryllium’, ‘Boron’, ‘Nitrogen’, ‘Carbon’]

3. Append

Another way to add something to the end of a list is to use the append method:

list2.append(“Nitrogen”)

Results in

[‘Hydrogen’, ‘Helium’, ‘Lithium’, ‘Beryllium’, ‘Boron’, ‘Carbon’, ‘Nitrogen’]

Remember, the + operation only concatenates a list to a list, so the equivalent expression involving + is

list2 = list2 + [“Nitrogen”]

4. Extend

The extend method does almost the same things as the + operator. With the definitions

a = [1,2,3,4,5]

b = [6,7,8,9,10]

print (a+b)

a.extend(b)

print(a)

The output is

[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

However, if append has been used instead of extend above,

a = [1,2,3,4,5]

b = [6,7,8,9,10]

print (a+b)

a.append(b)

print(a)

The result would have been

[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

[1, 2, 3, 4, 5, [6, 7, 8, 9, 10]]

5. Remove

The remove method does what is expected: it removes an element from the list. But unlike insert, for example, it does not do it using an index; the value to be remove is specified.

listl = [“Hydrogen”,”Helium”,”Lithium”,”Beryllium”,”Boron”, “Carbon”]

list1.remove(“Helium”)

results in the listl being [‘Hydrogen’, ‘Lithium’, ‘Beryllium’, ‘Boron’, ‘Carbon’]. Unfortunately, if the component being deleted is not a member of the list, then an error occurs. There are ways to deal with that, or a test can be made for trying to delete an item:

if “Nitrogen” in list1:

list1.remove(“Nitrogen”)

If there is more than a single instance of the item being removed, then only the first one is removed.

6. Index

When discussing tuples, we noted that the index method looked through the tuple and found the index at which a specified item occurred. The index method for lists works in the same way.

listl = [“Hydrogen”,”Helium”,”Lithium”,”Beryllium”,”Boron”, “Carbon”]

print (list1.index(“Boron”))

prints “4,” because the string “Boron” appears at index 4 in this list (starting from 0, of course). If there is more than one occurrence of “Boron” in the list, then the index of the first one (i.e., the smallest index) is returned. If the value is not found in the string, then an error occurs. It might be appropriate to check:

if “Boron” in listl:

print (list1.index(“Boron”))

7. Pop

The pop method is effectively the reverse or inverse of append. It removes the last item (i.e., the one with the largest index) from the list. If the list is empty, then an error occurs. For example,

listl = [“Hydrogen”,”Helium”,”Lithium”,”Beryllium”,”Boron”, “Carbon”]

list1.pop()

print (list1)

prints the result

[‘Hydrogen’, ‘Helium’, ‘Lithium’, ‘Beryllium’, ‘Boron’]

To avoid the error that can occur if the list is empty, simply check to see that the length of the list is greater than zero before using pop:

if len(list1) > 0:
list1.pop()

The method is called pop because it represents a way to implement the opera­tion of the same name on a data structure called a stack.

8. Sort

This method places the components of a list into ascending order. We use the listl variable that has been used so often for the following code:

listl = [“Hydrogen”,”Helium”,”Lithium”,”Beryllium”,”Boron”, “Carbon”]

list1.sort()

print(listl)

The result is

[‘Beryllium’, ‘Boron’, ‘Carbon’, ‘Helium’, ‘Hydrogen’, ‘Lithium’]

which is in alphabetic order. The method sorts integers and floating point num­bers, as well. Strings and numbers cannot be mixed, though, because they cannot be compared. So

list2 = [“Hydrogen”,1,”Helium”,2,”Lithium”,3,”Beryllium”,4, “Boron”,5]

list2.sort()

results in an error that is something like

list2.sort()

TypeError: unorderable types: int() < str()

The meaning of this error should be clear. Things of type int (integer) and things of type str (string) cannot be compared against each other and so cannot be placed in a sensible order if mixed. For sort to work properly, all of the ele­ments of the list must be of the same type. It is always possible to convert one type of thing into another, and in Python converting an integer to a string is ac­complished with the str() function; a string is converted into an integer using int(). str(3) would result in “3,” and int(“12”) is 12. An error will occur if it is not possible, so int(12.2) will fail.

If each element of a list is itself a list, it can still be sorted. Consider the fol­lowing list:

z = [[“Hydrogen”,3],[“Hydrogen”,2],[“Lithium”,3], [“Beryllium”,4],[“Boron”,5]]

When sorted this becomes:

[[‘Beryllium’,4],[‘Boron’,5],[‘Hydrogen’,2],[‘Hydrogen’,3],[‘Lithium’,3]]

Each component of this list is compatible with the others, consisting of a string and an integer. Thus, they can be compared against each other. Notice that there are two entries for hydrogen: one with a number 2 and one with a number 3. The sort method arranges them correctly. A list is sorted by individual elements in sequence order, so the first thing tested would be the string. If those are the same, then the next element is checked. That’s an integer, so the component with the smallest integer component will come first.

9. Reverse

In any sequence, the order of the components within it is important. Revers­ing that order is a logical operation to provide, but may not be used very often. One instance where it can be important is after a sort. The sort method always places components into ascending order. If they are supposed to be in descend­ing order, then the reverse method becomes valuable. As an example, consider sorting the list q:

q = [5, 6, 1, 5, 4, 9, 9, 1, 6, 3]

q.sort()

The value of q at this point is

[1, 1, 3, 4, 5, 5, 6, 6, 9, 9]

To place this list in descending order, the reverse method is used:

q.reverse()

and the result is

[9, 9, 6, 6, 5, 5, 4, 3, 1, 1]

It is hard to say whether ascending order is needed more often than descend­ing order. Names are often sorted smallest first (ascending), but dates are more likely to require more recent dates before later ones (descending).

10. Count

The count method is used to determine how many times a potential compo­nent of a list actually occurs. It does not return the number of elements in the list – that job is done by the len function. We use the list q as an example:

q = [5, 6, 1, 5, 4, 9, 9, 1, 6, 3]

print (1,q.count(1),    2, q.count(2), 3, q.count(3), 99,

q.count(99))

This code results in the output

1 2                2 0                3 1              99 0

where the spacing is enhanced for emphasis. This says that there are 2 instances of the number 1 (1,2) in the list, zero instances of 2 (2,0), one instance of the num­ber 3 (3,1), and none of 99 (99,0).

11. List Comprehension

Two mechanisms were discussed for creating a list of items. The first is to use constants, as in the list q in the previous section. The second appends items to a list, and this could be done within a loop. Making a list of perfect squares could be done like this:

t = []

for i in range(0,10):
t = t + [i*i]

which creates the list [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]. This kind of approach is common enough that a special syntax has been created for it in Python – the list comprehension.

The basic idea is simple enough, although some specific cases are compli­cated. In the situation above involving perfect squares, the elements in the list are some function of the index. When that is true, the loop, index, and function can be given within the square brackets as a definition of the list. The list t could be defined as

tt = [i**2 for i in range(10)]

The for loop is within the square brackets, indicating that the purpose is to define components of the list. The variable i here is the loop variable, and i**2 is the function that creates the elements from the index. This is a simple example of a list comprehension.

We create random integer values with the following code: tt = [random.randint(0,100) for i in range(10)]

We can put the first six elements in all uppercase letters, as well:

listl = [“Hydrogen”,”Helium”,”Lithium”,”Beryllium”,”Boron”, “Carbon”]

ss = [i.upper() for i in listl]

This is a very effective way to create lists, but it does depend on having a known connection between the index and the element.

12. HIM Lists and Tuples

A tuple can be converted into a list. Lists have a greater functionality than tuples; that is, they provide more operations and greater ability to represent data. However, they are more complicated and require more computer resources. If something can be represented as a tuple, then it is likely best to do so. A tuple is designed to be a collection of elements that as a whole represent some more com­plicated object, but that individually are perhaps of different types. This is rather like a C struct or Pascal record. A list is more often used to hold a set of elements that all have the same type, more like an array. This is a good way to think of the two types when deciding what to use to solve a specific problem.

Python provides tools for conversion. The built-in function list takes a tuple and converts it into a list; the function tuple does the reverse, taking a list and turning it into a tuple. For example, converting list1 into a tuple involves the fol­lowing code:

tuplel = tuple(listl)

print(tuplel)

This code yields

(‘Hydrogen’, ‘Helium’, ‘Lithium’, ‘Beryllium’, ‘Boron’, ‘Carbon’)

This is seen to be a tuple because of the “(“ and “)” delimiters. The reverse operation

v = list(tuplel) print(v)

prints the text line

[‘Hydrogen’, ‘Helium’, ‘Lithium’, ‘Beryllium’, ‘Boron’, ‘Carbon’] and the square brackets indicate this is a list.

13. Exceptions

Exceptions are the usual way to check for errors of indexing and membership in lists. The error is allowed to occur, but an exception is tested and handled in the case where, for example, an item being deleted is not in the list.

Problem: Delete the element Helium from a list.

Earlier, as an example of the remove method, a program snippet was written to delete the element Helium from a list of elements.

listl = [“Hydrogen”,”Helium”,”Lithium”,”Beryllium”,”Boron”, “Carbon”]

if “Helium” in listl:

list1.remove(“Helium”)

Because the list listl may not have Helium as one of the components a check was made before an attempt to delete it. An attempt to delete an element from a list where the element does not appear in that list results in an AttributeError. Rather than perform an explicit test, a Python programmer would more likely use an exception here. The error can be caught as follows:

listl = [“Hydrogen”,”Helium”,”Lithium”,”Beryllium”,”Boron”, “Carbon”]

try:

list1.remove(“Helium”)

except:

print (‘Can’t find Helium’)

The advantage of this over allowing the error to occur is that the program can continue to execute.

Problem: Delete a specified element from a list.

Given the same list, read an element from the keyboard and delete that ele­ment from the list. The basic code is the same, but now the string is entered and could be anything at all. It’s easier to test a program when it can be made to fail on purpose. The name is entered using the input function and is used as the param­eter to remove. Now it is possible to test all of the code in this program without changing it. First, here is the program:

listl = [“Hydrogen”,”Helium”,”Lithium”,”Beryllium”,”Boron”, “Carbon”]

s = input(“Enter:”) try:

listl.remove(s)

except:

print (‘Can’t find ‘, s) print (listl)

Properly testing a program means executing all of the statements that com­prise it and ensuring that the answer given is correct. In this case, first delete an element that is a part of the list. Try Lithium. Here is the output:

Enter: Lithium

[‘Hydrogen’, ‘Helium’, ‘Beryllium’, ‘Boron’, ‘Carbon’]

This is correct. These are the statements that were executed in this instance:

listl = [“Hydrogen”,”Helium”,”Lithium”,”Beryllium”,”Boron”, “Carbon”]

s = input(“Enter:”)

try:

list1.remove(s) # This was successful

print (listl)

Now try to delete “Oxygen.” The output is

Enter: Oxygen

Can’t find Oxygen

[‘Hydrogen’, ‘Helium’, ‘Lithium’, ‘Beryllium’, ‘Boron’, ‘Carbon’]

This is correct. These statements were executed:

listl = [“Hydrogen”,”Helium”,”Lithium”,”Beryllium”,”Boron”, “Carbon”]

s = input(“Enter:”)

try:

list1.remove(s)     # this was not successful

except:

print (‘Can’t find ‘, s) print (list1)

All of the code in the program has been executed and the results checked for both major situations. For any major piece of software this kind of testing is exhausting, but it is really the only way to minimize the errors that remain in the final program.

 

Source: Parker James R. (2021), Python: An Introduction to Programming, Mercury Learning and Information; Second edition.

Leave a Reply

Your email address will not be published. Required fields are marked *