THEORY AND PRACTICE
-
Input and Output Data
- Tasks
-
Conditions
- Tasks
-
For Loop
- Tasks
-
Strings
- Tasks
-
While Loop
- Tasks
-
Lists
- Tasks
-
Two-Dimensional Arrays
- Tasks
-
Dictionaries
- Tasks
-
Sets
- Tasks
-
Functions and Recursion
- Tasks
Lesson 6. Lists and List methods in python
Introduction to the lists
Lists in Python: definition and data types
Lists are one of the most versatile and frequently used built—in data types in Python. At its core, a list is an ordered and mutable collection of objects. A single list can contain items of completely different types.
# To find out the type of a variable, use the function type()
my_list = [1, 2, 3]
print(type(my_list))
Basic properties of lists
- Orderliness (Ordered): The items in the list are stored in a specific order. Each element has its own index (ordinal number), and this order will not change unless you change it yourself.
- Mutability: You can change the list after it is created: add, delete, or modify its elements. This is the key difference from tuples.
Examples of lists with different data types
Python lists are extremely flexible and can contain any type of data, even mixed together.
# List of integers
numbers = [1, 5, -10, 23]
# List of lines
strings = ["hello", "world", "python"]
# Mixed list: numbers, strings, booleans, and even None
mixed_list = [10, "apple", True, 3.14, None]
print(numbers)
print(strings)
print(mixed_list)
Creating lists in Python
Creating an empty list
There are two main ways to create an empty list, which can be filled with data later.
# Method 1: using square brackets (the most common)
empty_list_1 = []
# Method 2: using the list() constructor
empty_list_2 = list()
print(f"Empty list 1: {empty_list_1}")
print(f"Empty list 2: {empty_list_2}")
A list with elements of the same type
Lists are most often used to store homogeneous data.
# List of integers
integer_list = [10, 20, 30, 40, 50]
# List of strings
string_list = ["Moscow", "Saint Petersburg", "Kazan"]
print(integer_list)
print(string_list)
Mixed and nested lists
The lists may contain other lists. Such structures are called nested or two-dimensional lists and are often used to represent matrices or tables.
# Mixed list
mixed_data = ["Alexey", 35, "Programmer", 185.5, True]
# Nested list (2x3 matrix)
matrix = [
[1, 2, 3],
[4, 5, 6]
]
print(f"Employee data: {mixed_data}")
print(f"Matrix: {matrix}")
# Access to the element of the nested list: matrix[row][column]
print(f"Element in the first row, second column: {matrix[0][1]}") # Will output 2
Accessing list items
Indexing from the beginning (positive indexes)
Indexing in Python starts at 0. The first element has an index of 0, the second has an index of 1, and so on.
fruits = ["apple", "banana", "cherry", "orange"]
# We get the first element
first_fruit = fruits[0]
print(f"First fruit: {first_fruit}") # 'apple'
# We get the third element
third_fruit = fruits[2]
print(f"Third fruit: {third_fruit}") # 'cherry'
Indexing from the end (negative indexes)
Negative indexing allows accessing elements from the end of the list. -1 is the last element, -2 is the penultimate, etc.
fruits = ["apple", "banana", "cherry", "orange"]
# Getting the last element
last_fruit = fruits[-1]
print(f"Last fruit: {last_fruit}") # 'orange'
# We get the penultimate element
second_to_last_fruit = fruits[-2]
print(f"Penultimate fruit: {second_to_last_fruit}") # 'cherry'
Slices
Slices are a powerful tool for getting a part of a list. They create a new list without changing the original one.
Basic syntax: list[start:stop:step]
start: the index from which the slice starts (inclusive). If omitted, the slice starts from 0.stop: the index where the slice ends (not inclusive!). If omitted, the slice goes to the end of the list.step: The step with which the elements are extracted. If omitted, the step is 1.
numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
# Slice from the 2nd to the 5th element (indexes 1 to 4)
subset = numbers[1:5]
print(f"Slice from 1 to 4 index: {subset}") # [1, 2, 3, 4]
# Slice from the beginning to the 4th element (index 3)
first_part = numbers[:4]
print(f"Slice from start to index 3: {first_part}") # [0, 1, 2, 3]
# Slice from the 5th element (index 4) to the end
last_part = numbers[4:]
print(f"Slice from index 4 to the end: {last_part}") # [4, 5, 6, 7, 8, 9]
# Getting every second element
every_second = numbers[::2]
print(f"Every second element: {every_second}") # [0, 2, 4, 6, 8]
# Flip the list using a slice (step -1)
reversed_list = numbers[::-1]
print(f"Inverted list: {reversed_list}") # [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
Changing list items
Assigning a value by index
Since the lists are changeable, you can easily replace one or more items.
colors = ["red", "green", "blue"]
print(f"Source list: {colors}")
# Changing the second element (index 1)
colors[1] = "yellow"
print(f"After changing one element: {colors}")
# You can also change the whole slice
colors[0:2] = ["orange", "purple"]
print(f"After changing the slice: {colors}")
Adding items to the list
The append() method
Adds one item to the very end of the list.
numbers = [1, 2, 3]
print(f"Before append: {numbers}")
numbers.append(4)
print(f"After append(4): {numbers}")
Method insert()
Inserts an element at the specified position (index).
letters = ['a', 'c', 'd']
print(f"Before insert: {letters}")
# Insert 'b' into the position with index 1
letters.insert(1, 'b')
print(f"After insert(1, 'b'): {letters}")
The extend()method
Expands the list by adding to the end all the elements from another sequence (for example, another list).
list1 = [1, 2, 3]
list2 = [4, 5, 6]
print(f"Before extend: list1 = {list1}")
list1.extend(list2)
print(f"After extend(list2): list1 = {list1}")
# Compare with append:
list3 = [1, 2, 3]
list3.append(list2) # append will add list2 as a single nested element
print(f"Result from append: {list3}") # [1, 2, 3, [4, 5, 6]]
Removing items from the list
Method remove()
Deletes the first occurrence of the specified value found. If the value is not found, it causes the
error ValueError.
pets = ["cat", "dog", "hamster", "dog"]
print(f"Before remove: {pets}")
pets.remove("dog") # Will delete the first occurrence of "dog"
print(f"After remove('dog'): {pets}")
Method pop()
Deletes an element at the specified index and returns it. If no index is specified, deletes and returns the last element.
items = ["book", "pen", "laptop", "mouse"]
print(f"Before pop: {items}")
# Deleting an item with index 1 and saving it
removed_item =items.pop(1)
print(f"Deleted item: {removed_item}")
print(f"After pop(1): {items}")
# Removing the last element
last_item = items.pop()
print(f"Last item deleted: {last_item}")
print(f"After pop(): {items}")
Method clear()
Removes all items from the list, making it empty.
data = [1, 2, 3, 4, 5]
print(f"Before clear: {data}")
data.clear()
print(f"After clear: {data}")
Searching for items in the list
index() method
Returns the index of the first occurrence of the specified value. If the value is not found, it causes the error ValueError.
numbers = [10, 20, 30, 40, 20, 50]
# Find the index of the first occurrence of the number 30
idx = numbers.index(30)
print(f"Index of the number 30: {idx}") # 2
# You can specify the initial index for the search
idx_after_3 = numbers.index(20, 3) # Search for 20 starting from index 3
print(f"Index of the number 20 after the 3rd position: {idx_after_3}") # 4
Method count()
Calculates how many times the specified value occurs in the list.
grades = ['A', 'B', 'A', 'C', 'A', 'B']
# Counting the number of grades 'A'
count_a = grades.count('A')
print(f"Number of ratings of 'A': {count_a}") # 3
Sorting lists
Method sort()
Sorts the list in place, that is, it modifies the original list. It doesn't return anything.
numbers = [3, 1, 4, 1, 5, 9, 2, 6]
print(f"Source list: {numbers}")
numbers.sort()
print(f"Sorted list: {numbers}")
Function sorted()
Returns a new sorted list, leaving the original one unchanged.
numbers = [3, 1, 4, 1, 5, 9, 2, 6]
print(f"Source list: {numbers}")
sorted_numbers = sorted(numbers)
print(f"New sorted list: {sorted_numbers}")
print(f"The original list remains unchanged: {numbers}")
Sorting in reverse order
Both methods, sort() and sorted(), take the optional argument reverse=True.
numbers = [3, 1, 4, 1, 5, 9, 2, 6]
# Sort in place in reverse order
numbers.sort(reverse=True)
print(f"Sort sort(reverse=True): {numbers}")
# Create a new list sorted in reverse order
new_sorted_desc = sorted([10, 50, 20], reverse=True)
print(f"Sort sorted(reverse=True): {new_sorted_desc}")
Reversing list items
Method reverse()
Reverses the order of the elements in the list in place.
letters = ['a', 'b', 'c', 'd']
print(f"Before reverse: {letters}")
letters.reverse()
print(f"After reverse: {letters}")
Function reversed()
Returns a iterator that traverses the list in reverse order. The original list does not change. To
get a list, wrap the result in list().
letters = ['a', 'b', 'c', 'd']
print(f"Source list: {letters}")
reversed_iterator = reversed(letters)
reversed_list = list(reversed_iterator)
print(f"New inverted list: {reversed_list}")
print(f"The original list has not changed: {letters}")
# As you remember, this can also be done by slicing
reversed_by_slice = letters[::-1]
print(f"Inverted list through slice: {reversed_by_slice}")
Copying lists
Shallow slicing
Assigning new_list = old_list does not create a copy, but only a new reference to the same object. To
create an independent copy, you can use a slice [:].
original_list = [1, 2, 3]
# Incorrect copying (just a link)
ref_list = original_list
ref_list[0] = 99
print(f"ref_list has been changed, and original_list has also changed: {original_list}") # [99, 2, 3]
# Correct cross-section copying
original_list = [1, 2, 3] # Return the original value
copied_list = original_list[:]
copied_list[0] = 55
print(f"Changed copied_list: {copied_list}") # [55, 2, 3]
print(f"original_list has not changed: {original_list}") # [1, 2, 3]
copy() method
The copy() method does the same thing as the slice [:] — it creates a surface copy of the
list.
original_list = [10, 20, 30]
# Copying using the copy() method
copied_list = original_list.copy()
copied_list[0] = 111
print(f"Changed the copy: {copied_list}")
print(f"The original has not changed: {original_list}")
Table of basic list methods
Array methods in python
| Method | Description | Code example | What does it return? |
|---|---|---|---|
append(x) |
Adds the x element to the very end of the list. |
a = [1, 2]
a.append(3)
print(a) # -> [1, 2, 3] |
None |
extend(iterable) |
Expands the list by adding to the end all the elements from the passed iterable object (for example, another list). | a = [1, 2]
b = [3, 4]
a.extend(b)
print(a) # -> [1, 2, 3, 4] |
None |
insert(i, x) |
Inserts the x element at the position with the i index. |
a = [1, 3]
a.insert(1, 2)
print(a) # -> [1, 2, 3] |
None |
remove(x) |
Deletes the first value found in the list x. If there is no such element, it causes the error ValueError. |
a = [1, 2, 3, 2]
a.remove(2)
print(a) # -> [1, 3, 2] |
None |
pop([i]) |
Deletes the element at position i and returns it. If the i index is not specified, deletes
and returns the last element. |
a = [1, 2, 3]
x = a.pop(1)
print(a, x) # -> [1, 3] 2 |
Deleted element |
clear() |
Clears the list by deleting all items from it. | a = [1, 2, 3]
a.clear()
print(a) # -> [] |
None |
index(x[, start[, end]]) |
Returns the index of the first occurrence of the x element. You can limit the search to a slice [start:end]. |
a = ['a', 'b', 'c']
i = a.index('b')
print(i) # -> 1 |
The element's index (number) |
count(x) |
Returns the number of occurrences of the x element in the list. |
a = [1, 2, 3, 2]
c = a.count(2)
print(c) # -> 2 |
Number of occurrences (number) |
sort(key=None, reverse=False) |
Sorts the list items in place (in-place). key is a function for calculating the key, reverse=True for sorting in descending order. |
a = [3, 1, 2]
a.sort()
print(a) # -> [1, 2, 3] |
None |
reverse() |
Expands the order of the elements in the list in place. | a = [1, 2, 3]
a.reverse()
print(a) # -> [3, 2, 1] |
None |
copy() |
Creates and returns a shallow copy of the list. Equivalent to the [:] slice. |
a = [1, 2]
b = a.copy()
b.append(3)
print(a, b) # -> [1, 2] [1, 2, 3] |
New list (copy) |
Important point: many methods, such as sort(), reverse(), append() and others,
modify the list "in-place" and return None. This is a common cause of errors for beginners who try to
assign the result of such an operation to another variable.
Features of working with lists of different types
String lists and working with join
The string method .join() allows you to combine the elements of the string list into a single line with
the specified separator.
words = ["Python", "is", "awesome"]
# Combining words separated by a space
sentence = " ".join(words)
print(sentence) # "Python is awesome"
# Comma-separated
csv_string = ",".join(words)
print(csv_string) # "Python,is,awesome"
Lists of numbers and operations on them
It is convenient to work with lists of numbers using built-in functions and generators.
numbers = [1, 2, 3, 4, 5]
# Getting a new list with squares of numbers (see the section about generators)
squares = [x * x for x in numbers]
print(f"Squares of numbers: {squares}")
Lists of boolean values and functions all(), any()
all(list)returnsTrueif all the list items are true.any(list)returnsTrueif at least one element of the list is true.
bool_list_1 = [True, True, True]
bool_list_2 = [True, False, True]
bool_list_3 = [False, False, False]
print(f"all(bool_list_1): {all(bool_list_1)}") # True
print(f"all(bool_list_2): {all(bool_list_2)}") # False
print(f"any(bool_list_2): {any(bool_list_2)}") # True
print(f"any(bool_list_3): {any(bool_list_3)}") # False
Two-dimensional lists and their traversal
Nested loops are used to traverse two-dimensional lists (matrices).
matrix = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
]
# Go through the matrix and print each element
for row in matrix: # Iterate along the lines first
for element in row: # Then by elements in each row
print(element, end=" ")
print() # Jumps to a new row after each row of the matrix
Iterating through lists
Simple iteration of elements
The most common method is the for loop.
colors = ["red", "green", "blue"]
for color in colors:
print(f"Current color: {color}")
Iteration using enumerate()
When you need not only an element, but also its index, use enumerate().
colors = ["red", "green", "blue"]
for index, color in enumerate(colors):
print(f"Element with index {index}: {color}")
List Comprehensions
This is an elegant and Pythonic way to create lists based on other sequences.
The simplest generators
Syntax: [expression for element in sequence]
# Creating a list of numbers from 0 to 9
numbers = [i for i in range(10)]
print(numbers) # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
# Creating a list of squares
squares = [x**2 for x in range(1, 6)]
print(squares) # [1, 4, 9, 16, 25]
Generators with condition (filtering)
Syntax: [expression for element in sequence if condition]
# Create a list of only even numbers from 0 to 10
even_numbers = [x for x in range(11) if x % 2 == 0]
print(even_numbers) # [0, 2, 4, 6, 8, 10]
# Create a list of string lengths that are longer than 3 characters
words = ["apple", "cat", "window", "dog"]
long_word_lengths = [len(word) for word in words if len(word) > 3]
print(long_word_lengths) # [5, 6]
Built-in functions for working with lists
function len() - the length of the list
my_list = [10, 20, 30]
print(len(my_list)) # 3
the sum()function is the sum of the elements
Works only for lists containing numbers.
numbers = [1, 2, 3, 4, 5]
print(sum(numbers)) # 15
function max() and min()
Find the maximum and minimum elements in the list.
numbers = [10, 5, 100, -2]
print(f"Maximum: {max(numbers)}") # 100
print(f"Minimum: {min(numbers)}") # -2
the zip()
function combines several lists into one, creating pairs (tuples) of elements with the same indexes.
names = ["Anna", "Boris", "Victor"]
ages = [25, 30, 35]
zipped_data = zip(names, ages)
print(list(zipped_data)) # [('Anna', 25), ('Boris', 30), ('Victor', 35)]
function map()
Applies a function to each item in the list. Returns an iterator.
numbers = [1, 2, 3, 4]
# Apply the str function to all elements to turn them into strings
string_numbers = map(str, numbers)
print(list(string_numbers)) # ['1', '2', '3', '4']
the filter()function
Filters the list, leaving only those elements for which the condition function returns True.
def is_positive(n):
return n > 0
numbers = [-10, 5, 0, -2, 8]
positive_numbers = filter(is_positive, numbers)
print(list(positive_numbers)) # [5, 8]
Additional tasks and examples
Rotating the list (shifting elements)
Task: move the list [1, 2, 3, 4, 5] move 2 elements to the left to get [3, 4, 5, 1, 2].
Cross-sectional solution
This is the simplest and most elegant way.
my_list = [1, 2, 3, 4, 5]
shift = 2
# Connecting the slice, starting with the shift, with the slice before the shift
rotated_list = my_list[shift:] + my_list[:shift]
print(rotated_list) # [3, 4, 5, 1, 2]
Removing duplicates using a set
Sets (set) in Python cannot contain duplicates. By converting the list to a set and
back, you can easily remove all repetitions. The order of the elements may not be preserved.
numbers_with_duplicates = [1, 2, 3, 2, 4, 1, 5, 5]
# Convert to a set to remove duplicates, and back to the list
unique_numbers = list(set(numbers_with_duplicates))
print(unique_numbers) # [1, 2, 3, 4, 5] ( the order may be different)
Splitting the list into chunks
Task: split the list [1, 2, 3, 4, 5, 6, 7, 8] for chunks of size 3.
long_list = [1, 2, 3, 4, 5, 6, 7, 8]
chunk_size = 3
# Using a generator and slices
chunks = [long_list[i:i + chunk_size] for i in range(0, len(long_list), chunk_size)]
print(chunks) # [[1, 2, 3], [4, 5, 6], [7, 8]]
Converting a list of lists into a flat list
Task: turn [[1, 2], [3, 4], [5]] in [1, 2, 3, 4, 5].
nested_list = [[1, 2], [3, 4], [5]]
# Using a nested list generator
flat_list = [item for sublist in nested_list for item in sublist]
print(flat_list) # [1, 2, 3, 4, 5]