3.2. Python Lists#

In Python, lists are one of the fundamental and versatile data structures that play a crucial role in a wide range of programming tasks. Lists provide a flexible way to store and manipulate collections of items, allowing you to work with sequences of elements efficiently. Whether you need to organize data, manage sets of values, or perform various operations on a group of items, Python lists offer a powerful tool to help you accomplish these tasks. This section explores the key features, operations, and best practices when working with lists in Python, empowering you with the knowledge to harness the full potential of this essential data structure [Downey, 2015, Python Software Foundation, 2023]:

3.2.1. List Operations#

3.2.1.1. Creating a List#

In Python, you can create a list to store multiple elements of different data types. Lists are mutable, meaning you can add, remove, and modify elements after creating the list. To create a list, you can use square brackets [ ] and separate the elements with commas.

Example: Here’s an example of how to create a list in Python:

# Empty list
empty_list = []

# List with elements
numbers = [1, 2, 3, 4, 5]
mixed_list = [1, "hello", True, 3.14]
fruits = ['Apple', 'Banana', 'Grape', 'Orange', 'Mango', 'Kiwi', 'Papaya',
          'Pineapple', 'Watermelon', 'Strawberry', 'Lemon', 'Apricot',
          'Cherry', 'Avocado', 'Peach', 'Pomegranate', 'Fig', 'Grapefruit',
          'Plum', 'Carambola', 'Jackfruit', 'Lychee', 'Pear', 'Guava']

3.2.1.2. Accessing Elements#

Once you have created a list, you can access its elements using indexing. Indexing in Python starts from 0, so the first element is accessed using index 0, the second element with index 1, and so on. Here’s how you can access elements in a list:

../_images/List_representation.png

Fig. 3.4 Visual representation of the ‘fruits’ list.#

# Access elements by index
first_element = fruits[0] 
print(f'First Element: {first_element}')
last_element = fruits[-1]
print(f'Last Element: {last_element}')
First Element: Apple
Last Element: Guava

3.2.1.3. List Slicing#

You can also use slicing to get a portion of the list:

# Slicing - Get a portion of the list
sliced_ = fruits[1:4]
print(sliced_)
['Banana', 'Grape', 'Orange']

3.2.1.4. Modifying List Elements#

Lists possess mutability, enabling you to alter their individual elements.

Example:

fruits = ["Apple", "Banana", "Orange"]

# Initial list
print("Initial List:")
print(fruits)

# Update an element
fruits[1] = "Grapes"
print("\nUpdated List (Element at Index 1 changed to 'Grapes'):")
print(fruits)

# Append an element to the end of the list
fruits.append("Mango")
print("\nUpdated List (Added 'Mango' to the end):")
print(fruits)

# Insert an element at a specific index
fruits.insert(1, "Kiwi")
print("\nUpdated List (Inserted 'Kiwi' at Index 1):")
print(fruits)

# Remove an element by value
fruits.remove("Grapes")
print("\nUpdated List (Removed 'Grapes' by Value):")
print(fruits)

# Remove an element by index
removed_element = fruits.pop(1)
print("\nRemoved Element:", removed_element)
print("\nUpdated List (Removed Element at Index 1):")
print(fruits)
Initial List:
['Apple', 'Banana', 'Orange']

Updated List (Element at Index 1 changed to 'Grapes'):
['Apple', 'Grapes', 'Orange']

Updated List (Added 'Mango' to the end):
['Apple', 'Grapes', 'Orange', 'Mango']

Updated List (Inserted 'Kiwi' at Index 1):
['Apple', 'Kiwi', 'Grapes', 'Orange', 'Mango']

Updated List (Removed 'Grapes' by Value):
['Apple', 'Kiwi', 'Orange', 'Mango']

Removed Element: Kiwi

Updated List (Removed Element at Index 1):
['Apple', 'Orange', 'Mango']

Let’s explain each operation in the code step by step:

  1. fruits = ["Apple", "Banana", "Orange"]: This line initializes a Python list named fruits containing three string elements: “Apple,” “Banana,” and “Orange.”

  2. fruits[1] = "Grapes": This line updates an element in the list. It assigns the string “Grapes” to the element at index 1 in the fruits list. As a result, the list becomes ['Apple', 'Grapes', 'Orange'].

  3. fruits.append("Mango"): Here, an element is appended to the end of the list. The string “Mango” is added to the fruits list. After this operation, the list becomes ['Apple', 'Grapes', 'Orange', 'Mango'].

  4. fruits.insert(1, "Kiwi"): This line inserts an element at a specific index in the list. It inserts the string “Kiwi” at index 1. As a result, the list becomes ['Apple', 'Kiwi', 'Grapes', 'Orange', 'Mango'].

  5. fruits.remove("Grapes"): Here, an element is removed from the list based on its value. It searches for the first occurrence of “Grapes” in the fruits list and removes it. After this operation, the list becomes ['Apple', 'Kiwi', 'Orange', 'Mango'].

  6. removed_element = fruits.pop(1): This line removes an element from the list by specifying its index. It removes the element at index 1 (“Kiwi”) and assigns it to the variable removed_element. The fruits list is updated to ['Apple', 'Orange', 'Mango'], and removed_element holds the value “Kiwi.”

In summary, the provided code demonstrates various operations on a Python list:

  • Updating an element by assigning a new value to a specific index.

  • Appending an element to the end of the list using the append() method.

  • Inserting an element at a specific index using the insert() method.

  • Removing an element by its value using the remove() method.

  • Removing an element by its index using the pop() method and capturing the removed element in a variable.

3.2.1.5. List Concatenation and Repetition#

In Python, you can concatenate (combine) two or more lists into a single list using the + operator. This creates a new list containing all the elements from the original lists. The original lists remain unchanged. Here’s an example of list concatenation:

list1 = [1, 2, 3]
list2 = [4, 5, 6]
list3 = [7, 8, 9]

concatenated_list = list1 + list2 + list3
print(concatenated_list)  # Output: [1, 2, 3, 4, 5, 6, 7, 8, 9]
[1, 2, 3, 4, 5, 6, 7, 8, 9]

You can also use the * operator for list repetition. This creates a new list that repeats the elements of the original list a specified number of times.

Example: Here’s an example of list repetition:

list_to_repeat = [1, 2, 3]
repeated_list = list_to_repeat * 3
print(repeated_list)  # Output: [1, 2, 3, 1, 2, 3, 1, 2, 3]
[1, 2, 3, 1, 2, 3, 1, 2, 3]

Keep in mind that these operations create new lists, and the original lists are not modified. If you need to modify the original lists, you should use other list methods like append(), extend(), or slicing.

Example:

list1 = [1, 2, 3]
list2 = [4, 5, 6]

# Appending elements from list2 to list1
list1.append(list2)
print(list1)  # Output: [1, 2, 3, [4, 5, 6]]

# Extending list1 with elements from list2
list1.extend(list2)
print(list1)  # Output: [1, 2, 3, [4, 5, 6], 4, 5, 6]

# Slicing and modifying the original list
list1[3:4] = list2
print(list1)  # Output: [1, 2, 3, 4, 5, 6, 4, 5, 6]
[1, 2, 3, [4, 5, 6]]
[1, 2, 3, [4, 5, 6], 4, 5, 6]
[1, 2, 3, 4, 5, 6, 4, 5, 6]

As shown in the example, append() adds the entire list list2 as a single element at the end of list1. extend() adds each element of list2 to list1. Slicing with assignment replaces a part of the original list with the elements of list2.

3.2.1.6. List Length#

In Python, you can determine the length of a list (i.e., the number of elements in the list) using the built-in len() function. The len() function works for all kinds of sequences, including lists, tuples, strings, etc.

Example: Here’s how you can find the length of a list:

my_list = [10, 20, 30, 40, 50]
length_of_list = len(my_list)

print(length_of_list)  # Output: 5
5

In this example, the len() function is used to get the number of elements in the my_list list, and it returns the value 5 because there are five elements in the list. It’s worth noting that the len() function can also be used to find the length of other sequence types, such as strings:

my_string = "Hello, World!"
length_of_string = len(my_string)

print(length_of_string)  # Output: 13
13

In this case, the len() function returns 13 as there are 13 characters in the string, including spaces and punctuation.

3.2.2. List Sorting#

In Python, you can sort a list using the built-in sorted() function or by using the sort() method of the list object. Both methods allow you to sort the list in ascending order by default. If you need to sort the list in descending order, you can use the reverse=True argument.

3.2.2.1. Using the sorted() function#

The sorted() function returns a new sorted list while leaving the original list unchanged.

Example:

numbers = [5, 2, 8, 1, 9, 3]
sorted_numbers = sorted(numbers)

print(sorted_numbers)  # Output: [1, 2, 3, 5, 8, 9]
print(numbers)  # Output: [5, 2, 8, 1, 9, 3] (original list remains unchanged)
[1, 2, 3, 5, 8, 9]
[5, 2, 8, 1, 9, 3]

To sort the list in descending order, use the reverse=True argument:

numbers = [5, 2, 8, 1, 9, 3]
sorted_numbers_desc = sorted(numbers, reverse=True)

print(sorted_numbers_desc)  # Output: [9, 8, 5, 3, 2, 1]
[9, 8, 5, 3, 2, 1]

3.2.2.2. Using the sort() method:#

The sort() method sorts the list in-place, meaning it modifies the original list.

Example:

numbers = [5, 2, 8, 1, 9, 3]
numbers.sort()

print(numbers)  # Output: [1, 2, 3, 5, 8, 9] (original list is sorted)
[1, 2, 3, 5, 8, 9]

To sort the list in descending order, you can again use the reverse=True argument with the sort() method:

numbers = [5, 2, 8, 1, 9, 3]
numbers.sort(reverse=True)

print(numbers)  # Output: [9, 8, 5, 3, 2, 1] (original list is sorted in descending order)
[9, 8, 5, 3, 2, 1]

Remark

The advantages of using sorted() and .sort() methods in Python lists are contingent upon the specific context and the programmer’s preferences. Here, we outline the key distinctions and benefits associated with each method [Downey, 2015, Python Software Foundation, 2023]:

The sorted() function is a built-in feature capable of sorting any iterable object, extending beyond just lists. It yields a new sorted list and maintains the original object’s integrity. This proves valuable when retaining the initial order is paramount or when the sorted outcome serves an alternative purpose. For instance, sorted() can effectively organize tuples, sets, or dictionaries by their keys or values without modifying the original data structure.

Conversely, the .sort() method is exclusively tailored for lists and operates in-place, returning None. It optimizes memory usage by manipulating the existing list directly, without producing a new entity. This efficiency is particularly beneficial when the original list is dispensable, and memory conservation is a concern. An example application would be using .sort() to arrange a list of numerical values or strings in ascending or descending order.

3.2.3. List Membership#

In Python, you can check whether an element is present in a list using the in and not in operators. These operators return a Boolean value (True or False) depending on whether the element is found in the list or not.

Example: Here’s an example of how to use the in operator to check if an element is a member of a list:

fruits = ["Apple", "Banana", "Orange", "Grape", "Watermelon"]

# Check if "Apple" is in the list
print("Apple" in fruits)  # Output: True

# Check if "pear" is in the list
print("Pear" in fruits)  # Output: False
True
False

You can use the not in operator to check if an element is not present in the list:

fruits = ["Apple", "Banana", "Orange", "Grape", "Watermelon"]

# Check if "pear" is not on the list
print("Pear" not in fruits)  # Output: True

# Check if "Apple" is not on the list
print("Apple" not in fruits)  # Output: False
True
False

The in and not in operators can also be used with other data types, such as strings, tuples, dictionaries, and sets, to check for membership in those data structures.

3.2.4. List Iteration#

In Python, you can iterate over the elements of a list using various methods like a for loop or a while loop. Iteration allows you to process each element in the list one by one. Here are some common ways to iterate over a list:

3.2.4.1. Using a for loop#

Example:

fruits = ["Apple", "Banana", "Orange", "Grape"]

# Iterate over the elements using a for loop
for fruit in fruits:
    print(fruit)
Apple
Banana
Orange
Grape

3.2.4.2. Using the range() function and a for loop (to access elements by index)#

Example:

fruits = ["Apple", "Banana", "Orange", "Grape"]

# Iterate over the elements using a for loop and range()
for i in range(len(fruits)):
    print(fruits[i])
Apple
Banana
Orange
Grape

3.2.4.3. Using a while loop and an index#

Example:

fruits = ["Apple", "Banana", "Orange", "Grape"]

# Iterate over the elements using a while loop and an index
i = 0
while i < len(fruits):
    print(fruits[i])
    i += 1
Apple
Banana
Orange
Grape

3.2.5. List Comprehension#

List comprehension is a concise and powerful feature in Python that allows you to create new lists by applying an expression to each element of an existing iterable (e.g., a list, tuple, string, etc.). It provides a more compact and readable way to generate lists compared to traditional ‘for’ loops. The basic syntax of list comprehension is as follows:

new_list = [expression for item in iterable]

Here’s a breakdown of the components:

  • expression: The operation or transformation to be applied to each item in the iterable.

  • item: A variable that takes the value of each element in the iterable.

  • iterable: The existing sequence (e.g., list, tuple) that you want to iterate over.

Here are some examples to illustrate the usage of list comprehension:

Example: Creating a new list of squares of numbers from 0 to 4

# Creating a new list of squares of numbers from 0 to 4
squares = [x**2 for x in range(5)]
print(squares)  # Output: [0, 1, 4, 9, 16]
[0, 1, 4, 9, 16]

squares = [x**2 for x in range(5)]: This line demonstrates a Python list comprehension. It creates a new list called squares by iterating through the numbers in the range from 0 to 4 (inclusive) and squaring each number (x**2). So, for each value of x in the range, it calculates its square and adds it to the squares list.

  • for x in range(5): This part of the list comprehension iterates through the numbers 0, 1, 2, 3, and 4. x takes on each of these values one at a time.

  • x**2: This is the expression that calculates the square of the current x value.

Example: Converting a list of strings to uppercase

# Converting a list of strings to uppercase
fruits = ["Apple", "Banana", "Orange"]
uppercase_fruits = [fruit.upper() for fruit in fruits]
print(uppercase_fruits)  # Output: ['APPLE', 'BANANA', 'ORANGE']
['APPLE', 'BANANA', 'ORANGE']

uppercase_fruits = [fruit.upper() for fruit in fruits]: Here, a list comprehension is used to create a new list called uppercase_fruits. The list comprehension iterates through each element (fruit) in the fruits list and applies the upper() method to convert each string to uppercase. So, for each fruit in the list, it converts the string to all uppercase letters using the upper() method.

  • for fruit in fruits: This part of the list comprehension iterates through each string (fruit) in the fruits list.

  • fruit.upper(): This expression applies the upper() method to the current fruit string, transforming it into uppercase.

Example: Filter even numbers from a list

# Filter even numbers from a list
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
even_numbers = [num for num in numbers if num % 2 == 0]
print(even_numbers)  # Output: [2, 4, 6, 8, 10]
[2, 4, 6, 8, 10]

even_numbers = [num for num in numbers if num % 2 == 0]: Here, a list comprehension is used to create a new list called even_numbers. The list comprehension iterates through each element (num) in the numbers list and checks if the element is even. This is done using the condition num % 2 == 0, which checks if the remainder of dividing num by 2 is equal to 0. If the condition is true, the element is included in the even_numbers list.

  • for num in numbers: This part of the list comprehension iterates through each number (num) in the numbers list.

  • if num % 2 == 0: This is the condition that checks if the current num is even.

Example: Creating a list of tuples with elements and their corresponding squares

# Creating a list of tuples with elements and their corresponding squares
numbers = [1, 2, 3, 4, 5]
number_squares = [(num, num**2) for num in numbers]
print(number_squares)  # Output: [(1, 1), (2, 4), (3, 9), (4, 16), (5, 25)]
[(1, 1), (2, 4), (3, 9), (4, 16), (5, 25)]

number_squares = [(num, num**2) for num in numbers]: Here, a list comprehension is used to create a new list called number_squares. The list comprehension iterates through each element (num) in the numbers list and creates a tuple for each element. Each tuple consists of two values: the original number (num) and its square (num**2).

  • for num in numbers: This part of the list comprehension iterates through each number (num) in the numbers list.

  • (num, num**2): This expression creates a tuple with two values: num and its square, num**2.

Example: Filtering and Extracting Data from Python Lists with List Comprehensions

my_list = [10, 20, 30, 40, 50]

# Print the original list
print('Original List:')
print(my_list)

# Specify the condition for filtering
condition = lambda x: x > 30

# Create a new list containing items that meet the condition
new_list = [item for item in my_list if condition(item)]

# Print the new list
print('New List:')
print(new_list)
Original List:
[10, 20, 30, 40, 50]
New List:
[40, 50]
../_images/Lists_Filter.png

Fig. 3.5 A Visual Representation of the Previous Example Demonstrating the Creation of a New List Using the Condition lambda x: x > 30.#

Let’s break down the provided code step by step:

  1. my_list = [10, 20, 30, 40, 50]: This line initializes a Python list named my_list with a sequence of numbers.

  2. print('Original List:'): This line prints a message, ‘Original List:’, to indicate that the subsequent output will display the original list.

  3. print(my_list): Here, the contents of the my_list are printed. In this case, it will display the numbers [10, 20, 30, 40, 50].

  4. condition = lambda x: x > 30: This line defines a lambda function and assigns it to the variable condition. The lambda function takes a single argument x and returns True if x is greater than 30, and False otherwise. It defines the filtering condition.

  5. new_list = [item for item in my_list if condition(item)]: This line uses a list comprehension to create a new list called new_list. The list comprehension iterates through each element (item) in my_list and includes it in new_list only if it satisfies the condition defined by the condition lambda function (i.e., if item is greater than 30).

  6. print('New List:'): Similar to the earlier print statement, this line is used to indicate that the following output will display the new list.

  7. print(new_list): Finally, this line prints the contents of the new_list, which contains the elements from the original list that meet the specified condition. In this case, it will print [40, 50] because those are the values in my_list that are greater than 30.

Example: The previous example can be also done using the filter() Function:

my_list = [10, 20, 30, 40, 50]

# Print the original list
print('Original List:')
print(my_list)

# Define the condition for filtering
condition = lambda x: x > 30

# Use the filter() function to create an iterator of matching items
filtered_elements = filter(condition, my_list)

# Convert the iterator to a list
new_list = list(filtered_elements)

# Print the new list
print('New List:')
print(new_list)
Original List:
[10, 20, 30, 40, 50]
New List:
[40, 50]

An explanation of the provided code:

  1. my_list = [10, 20, 30, 40, 50]: This line creates a Python list named my_list containing a sequence of numbers.

  2. print('Original List:'): This line is used to display a message indicating that the following output will show the original list.

  3. print(my_list): This line prints the contents of the my_list, which is the original list. It will display the numbers [10, 20, 30, 40, 50] in this case.

  4. condition = lambda x: x > 30: Here, a lambda function is defined and assigned to the variable condition. This lambda function takes a single argument x and returns True if x is greater than 30, and False otherwise. This function will be used as a filter condition.

  5. filtered_elements = filter(condition, my_list): The filter() function is used with the condition lambda function and my_list as its arguments. This function creates an iterator called filtered_elements containing elements from my_list that satisfy the condition defined in the condition lambda function. In this case, it will contain elements greater than 30.

  6. new_list = list(filtered_elements): This line converts the iterator filtered_elements into a new list called new_list. The list() function is used to achieve this conversion.

  7. print('New List:'): Similar to the earlier print statement, this line is used to indicate that the following output will display the new list.

  8. print(new_list): Finally, this line prints the contents of the new_list, which contains the elements from the original list that meet the specified condition. In this case, it will print [40, 50] because those are the values in my_list that are greater than 30.

3.2.6. Finding the Index of Items in a Python List#

To locate the index of a specific item in a Python list, the index() method is employed. This method returns the index of the first occurrence of the specified item.

# Create a list of numbers
my_list = [10, 20, 30, 40, 50]

# Specify the value to find its index
value_to_find = 30

try:
    # Attempt to find the index of the specified value
    index = my_list.index(value_to_find)
    
    # If found, print the index
    print(f"The index of {value_to_find} is {index}")
except ValueError:
    # If the value is not in the list, handle the exception
    print(f"{value_to_find} is not in the list")
The index of 30 is 2
../_images/Lists_FindByIndex.png

Fig. 3.6 A Visual Representation of Locating the Index of Items in a Python List.#

Let’s break down the provided code step by step:

  1. my_list = [10, 20, 30, 40, 50]: This line initializes a Python list named my_list containing a sequence of numbers.

  2. value_to_find = 30: Here, a specific value, 30, is assigned to the variable value_to_find. This value represents the item we want to find the index of within my_list.

  3. try:: This line begins a try block, indicating that the following code will be attempted, and any potential errors will be handled in the except block.

  4. index = my_list.index(value_to_find): Inside the try block, the index() method is used on my_list to find the index of the value_to_find. If the specified value is present in the list, its index is assigned to the index variable.

  5. print(f"The index of {value_to_find} is {index}"): If the value_to_find is found in my_list, this line prints a message indicating the index of the value. It uses an f-string to insert the value of value_to_find and the index into the message.

  6. except ValueError:: This line specifies the exception that the code is prepared to handle, specifically the ValueError exception.

  7. print(f"{value_to_find} is not in the list"): Inside the except block, if the value_to_find is not present in my_list (resulting in a ValueError), this line prints a message stating that the value is not in the list.

3.2.7. Lists and Strings#

Lists and strings are fundamental Python data types, exhibiting both commonalities and significant disparities.

Similarities:

  1. Both lists and strings are sequences, ensuring ordered access to elements through indexing.

  2. Indexing and slicing are prevalent operations for both data types.

  3. Iteration through loops (e.g., for loops) is applicable for both lists and strings.

  4. Membership can be verified using the “in” keyword for both.

Differences:

  1. Mutability:

    • a. Lists are mutable, enabling element modification, addition, and removal after creation.

    • b. Strings are immutable; modifying individual characters post-creation is prohibited. Desired alterations necessitate creating a new string.

  2. Element Types:

    • a. Lists accommodate diverse data types—integers, strings, booleans, and even nested lists.

    • b. Strings encompass Unicode characters, limiting direct inclusion of dissimilar data types.

  3. Syntax:

    • a. Lists are defined within square brackets: my_list = [1, 2, 3, "hello"].

    • b. Strings are established using single or double quotes: my_string = "Hello, World!" or my_string = 'Hello, World!'.

Examples:

Mutability:

# Lists are mutable
my_list = [1, 2, 3]
my_list[1] = 100   # Now my_list becomes [1, 100, 3]

# Strings are immutable
my_string = "Hello"
# The following will raise an error since strings cannot be modified this way.
my_string[0] = "h"  # Raises TypeError: 'str' object does not support item assignment

Type of Elements:

my_list = [1, "hello", True, [4, 5]]
my_string = "Hello, World!"

Slicing and Iteration:

# Slicing works similarly for lists and strings
my_list = [1, 2, 3, 4, 5]
my_sublist = my_list[1:4]  # Extracts elements [2, 3, 4] from my_list

my_string = "Hello, World!"
substring = my_string[0:5]  # Extracts substring "Hello" from my_string

# Iteration using for loop for lists
for element in my_list:
    print(element)

# Iteration using for loop for strings
for char in my_string:
    print(char)
1
2
3
4
5
H
e
l
l
o
,
 
W
o
r
l
d
!

3.2.8. Creating a list from strings#

To create a list from a string, you can use list comprehension or the split() method. The split() method splits a string into a list of substrings based on a specified delimiter. Here are examples of both approaches:

3.2.8.1. Using list comprehension#

# Example string
my_string = "Hello, how, are, you?"

# Create a list from the string using list comprehension and split()
my_list = [word.strip() for word in my_string.split(",")]

print(my_list)
# Output: ['Hello', 'how', 'are', 'you?']
['Hello', 'how', 'are', 'you?']

In this example, we use split(",") to split the string at each comma (,) and obtain a list of words. The strip() method is used to remove any leading or trailing whitespaces from each word.

3.2.8.2. Using the split() method directly#

# Example string
my_string = "Python is a popular programming language."

# Create a list from the string using split()
my_list = my_string.split()

print(my_list)
# Output: ['Python', 'is', 'a', 'popular', 'programming', 'language.']
['Python', 'is', 'a', 'popular', 'programming', 'language.']

By default, split() without any arguments will split the string using whitespace as the delimiter, resulting in a list of words.