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) returns True if all the list items are true.
  • any(list) returns True if 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]