2.3. Python Lists#

In Python, lists are fundamental and versatile data structures that play a crucial role in various programming tasks. Lists provide a flexible way to store and manipulate collections of items, allowing efficient work with sequences of elements. Whether organizing data, managing sets of values, or performing various operations on groups of items, Python lists offer a powerful tool to 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, 2024].

2.3.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, use square brackets [ ] and separate the elements with commas.

Example: Creating 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'
]

2.3.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. Negative indexing allows access from the end of the list, with the last element at index -1, the second last at index -2, and so forth.

Example: Acessing elements in a 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

Table 2.5 demonstrates how positive and negative indexing works in Python, using a list of fruit names as an example:

  • Positive Index: Starts from 0 and increases by 1 for each subsequent element. For example, Apple is at index 0, Banana at index 1, and so on.

  • Negative Index: Starts from -1 for the last element and decreases by 1 for each preceding element. For example, Guava is at index -1, Pear at index -2, and so on.

This dual indexing system allows for flexible access to elements in a list, enabling both forward and backward traversal.

Table 2.5 Illustration of Positive and Negative Indexing in Python#

Positive Index

0

1

2

3

4

5

21

22

23

Element

Apple

Banana

Grape

Orange

Mango

Kiwi

Lychee

Pear

Guava

Negative Index

-24

-23

-22

-21

-20

-19

-3

-2

-1

2.3.3. List Slicing#

You can use slicing to get a portion of a list. Slicing is done by specifying a start and end index, and the sublist includes elements from the start index up to, but not including, the end index.

Example: Slicing a list:

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

In this example, sliced_ will contain the elements from index 1 to index 3 of the fruits list.

2.3.4. Modifying List Elements#

Lists are mutable, 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']

Explanations:

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

  2. fruits[1] = "Grapes": This updates the element at index 1 to “Grapes”. The list becomes ['Apple', 'Grapes', 'Orange'].

  3. fruits.append("Mango"): This appends “Mango” to the end of the list, resulting in ['Apple', 'Grapes', 'Orange', 'Mango'].

  4. fruits.insert(1, "Kiwi"): This inserts “Kiwi” at index 1, resulting in ['Apple', 'Kiwi', 'Grapes', 'Orange', 'Mango'].

  5. fruits.remove("Grapes"): This removes the first occurrence of “Grapes” from the list, resulting in ['Apple', 'Kiwi', 'Orange', 'Mango'].

  6. removed_element = fruits.pop(1): This removes the element at index 1 (“Kiwi”) and assigns it to removed_element. The list updates to ['Apple', 'Orange', 'Mango'].

2.3.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.

Example: 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: 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]

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.

2.3.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, and strings.

Example: Finding 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.

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.

2.3.7. 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.

2.3.7.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]

2.3.7.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 depend on 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, 2024]:

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.

2.3.8. 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: 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.

2.3.9. 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:

2.3.9.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

We also could do this 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

2.3.9.2. 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

2.3.10. 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]

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.

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]

In this example, the list comprehension [x**2 for x in range(5)] iterates through the numbers 0 to 4 (inclusive) and computes the square of each number. Each squared value is then added to the squares list.

  • for x in range(5): Iterates through the numbers 0, 1, 2, 3, and 4.

  • x**2: Computes 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']

In this example, the list comprehension [fruit.upper() for fruit in fruits] converts each string in the fruits list to uppercase using the upper() method.

  • for fruit in fruits: Iterates through each string in the fruits list.

  • fruit.upper(): Converts the current string to 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]

In this example, the list comprehension [num for num in numbers if num % 2 == 0] filters the numbers list to include only even numbers.

  • for num in numbers: Iterates through each number in the numbers list.

  • if num % 2 == 0: Includes the number in the new list only if it 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)]

In this example, the list comprehension [(num, num**2) for num in numbers] creates a list of tuples, where each tuple contains a number and its square.

  • for num in numbers: Iterates through each number in the numbers list.

  • (num, num**2): Creates a tuple with the number and its square.

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. 2.1 A Visual Representation of the Previous Example Demonstrating the Creation of a New List Using the Condition lambda x: x > 30.#

In this example, a lambda function condition = lambda x: x > 30 is used to filter elements greater than 30 from my_list. The list comprehension [item for item in my_list if condition(item)] creates a new list new_list containing elements that satisfy the condition.

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]

In this example, the filter() function is used with the lambda function condition to create an iterator filtered_elements containing elements greater than 30. The iterator is then converted to a list new_list.

2.3.11. 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. 2.2 A Visual Representation of Locating the Index of Items in a Python List.#

In this example, the index() method is used to find the index of value_to_find in my_list. If the value is found, its index is printed; otherwise, a ValueError is caught, and a message is printed indicating that the value is not in the list.

2.3.12. 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
!

2.3.13. 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:

2.3.13.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.

2.3.13.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.

Table 2.6 Various list operations in Python#

Operation

Syntax

Description

Example

Resulting List

Initialize a List

list_name = [elements]

Creates a new list with specified elements

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

['Apple', 'Banana', 'Orange']

Access an Element

list_name[index]

Retrieves the element at the specified index

fruit = fruits[0]

fruit = 'Apple'

Update an Element

list_name[index] = new_value

Updates the element at the specified index

fruits[1] = "Grapes"

['Apple', 'Grapes', 'Orange']

Append an Element

list_name.append(value)

Adds an element to the end of the list

fruits.append("Mango")

['Apple', 'Grapes', 'Orange', 'Mango']

Insert an Element

list_name.insert(index, value)

Inserts an element at the specified index

fruits.insert(1, "Kiwi")

['Apple', 'Kiwi', 'Grapes', 'Orange', 'Mango']

Remove by Value

list_name.remove(value)

Removes the first occurrence of the specified value

fruits.remove("Grapes")

['Apple', 'Kiwi', 'Orange', 'Mango']

Remove by Index

list_name.pop(index)

Removes and returns the element at the specified index

removed = fruits.pop(1)

removed = 'Kiwi'
['Apple', 'Orange', 'Mango']

Remove Last Element

list_name.pop()

Removes and returns the last element

removed = fruits.pop()

removed = 'Mango'
['Apple', 'Orange']

Length of List

len(list_name)

Returns the number of elements in the list

length = len(fruits)

length = 3

Check Existence

value in list_name

Checks if a value exists in the list

exists = "Apple" in fruits

exists = True

Concatenate Lists

list1 + list2

Combines two lists into one

new_list = fruits + ["Pear"]

['Apple', 'Orange', 'Mango', 'Pear']

Extend List

list_name.extend([elements])

Extends the list by appending elements from an iterable

fruits.extend(["Peach", "Plum"])

['Apple', 'Orange', 'Mango', 'Peach', 'Plum']

Reverse List

list_name.reverse()

Reverses the order of the elements in the list

fruits.reverse()

['Mango', 'Orange', 'Apple']

Sort List

list_name.sort()

Sorts the elements of the list in ascending order

fruits.sort()

['Apple', 'Banana', 'Orange']