ВУЗ: Не указан
Категория: Не указан
Дисциплина: Не указана
Добавлен: 05.12.2023
Просмотров: 828
Скачиваний: 3
ВНИМАНИЕ! Если данный файл нарушает Ваши авторские права, то обязательно сообщите нам.
СОДЕРЖАНИЕ
Глава 8. Списки, кортежи, множества и диапазоны
149
>>> arr = [ [1, 2], [3, 4] ] # Элементы имеют изменяемый тип (список)
>>> for i in arr: i[0] += 10
>>> arr # Список изменился
[[11, 2], [13, 4]]
Для генерации индексов элементов можно воспользоваться функцией range()
, которая воз- вращает объект-диапазон, поддерживающий итерации. С помощью такого диапазона внут- ри цикла for можно получить текущий индекс. Функция range()
имеет следующий формат: range([<Начало>, ]<Конец>[, <Шаг>])
Первый параметр задает начальное значение. Если он не указан, используется значение
0
Во втором параметре указывается конечное значение. Следует заметить, что это значение не входит в возвращаемый диапазон значений. Если параметр
<Шаг>
не указан, используется значение
1
. Для примера умножим каждый элемент списка на 2: arr = [1, 2, 3, 4] for i in range(len(arr)): arr[i] *= 2 print(arr) # Результат выполнения: [2, 4, 6, 8]
Можно также воспользоваться функцией enumerate(<Объект>[, start=0])
, которая на каж- дой итерации цикла for возвращает кортеж из индекса и значения текущего элемента спи- ска. Умножим каждый элемент списка на 2: arr = [1, 2, 3, 4] for i, elem in enumerate(arr): arr[i] *= 2 print(arr) # Результат выполнения: [2, 4, 6, 8]
Кроме того, перебрать элементы можно с помощью цикла while
, но нужно помнить, что он выполняется медленнее цикла for
. Для примера умножим каждый элемент списка на 2, ис- пользуя цикл while
: arr = [1, 2, 3, 4] i, c = 0, len(arr) while i < c: arr[i] *= 2 i += 1 print(arr) # Результат выполнения: [2, 4, 6, 8]
8.5. Генераторы списков и выражения-генераторы
В предыдущем разделе мы изменяли элементы списка следующим образом: arr = [1, 2, 3, 4] for i in range(len(arr)): arr[i] *= 2 print(arr) # Результат выполнения: [2, 4, 6, 8]
С помощью генераторов списков тот же самый код можно записать более компактно, к то- му же генераторы списков работают быстрее цикла for
. Однако вместо изменения исходно- го списка возвращается новый список: arr = [1, 2, 3, 4] arr = [ i * 2 for i in arr ] print(arr) # Результат выполнения: [2, 4, 6, 8]
150
Часть I. Основы языка Python
Как видно из примера, мы поместили цикл for внутри квадратных скобок, а также измени- ли порядок следования параметров, — инструкция, выполняемая внутри цикла, находится перед циклом. Обратите внимание и на то, что выражение внутри цикла не содержит опера- тора присваивания, — на каждой итерации цикла будет генерироваться новый элемент, которому неявным образом присваивается результат выполнения выражения внутри цикла.
В итоге будет создан новый список, содержащий измененные значения элементов исходного списка.
Генераторы списков могут иметь сложную структуру — например, состоять из нескольких вложенных циклов for и (или) содержать оператор ветвления if после цикла. Для примера получим четные элементы списка и умножим их на 10: arr = [1, 2, 3, 4] arr = [ i * 10 for i in arr if i % 2 == 0 ] print(arr) # Результат выполнения: [20, 40]
Этот код эквивалентен коду: arr = [] for i in [1, 2, 3, 4]: if i % 2 == 0: # Если число четное arr.append(i * 10) # Добавляем элемент print(arr) # Результат выполнения: [20, 40]
Усложним наш пример — получим четные элементы вложенного списка и умножим их на 10: arr = [[1, 2], [3, 4], [5, 6]] arr = [ j * 10 for i in arr for j in i if j % 2 == 0 ] print(arr) # Результат выполнения: [20, 40, 60]
Этот код эквивалентен коду: arr = [] for i in [[1, 2], [3, 4], [5, 6]]: for j in i: if j % 2 == 0: # Если число четное arr.append(j * 10) # Добавляем элемент print(arr) # Результат выполнения: [20, 40, 60]
Если выражение разместить внутри не квадратных, а круглых скобок, то будет возвращать- ся не список, а итератор. Такие конструкции называются выражениями-генераторами.
В качестве примера просуммируем четные числа в списке:
>>> arr = [1, 4, 12, 45, 10]
>>> sum((i for i in arr if i % 2 == 0))
26 8.6. Функции map(), zip(), filter() и reduce()
Встроенная функция map()
позволяет применить заданную в параметре функцию к каждому элементу последовательности. Она имеет такой формат: map(<Функция>, <Последовательность1>[, ..., <ПоследовательностьN>])
Функция map()
возвращает объект, поддерживающий итерации (а не список, как это было ранее в Python 2). Чтобы получить список в версии Python 3, возвращенный результат необ- ходимо передать в функцию list()
Глава 8. Списки, кортежи, множества и диапазоны
151
В качестве параметра
<Функция>
указывается ссылка на функцию (название функции без круглых скобок), которой будет передаваться текущий элемент последовательности. Внут- ри этой функции необходимо вернуть новое значение. Для примера прибавим к каждому элементу списка число 10 (листинг 8.1).
Листинг 8.1. Функция map() def func(elem):
""" Увеличение значения каждого элемента списка """ return elem + 10 # Возвращаем новое значение arr = [1, 2, 3, 4, 5] print( list( map(func, arr) ) )
# Результат выполнения: [11, 12, 13, 14, 15]
Функции map()
можно передать несколько последовательностей. В этом случае в функцию обратного вызова будут передаваться сразу несколько элементов, расположенных в после- довательностях на одинаковом смещении. Просуммируем элементы трех списков (лис- тинг 8.2).
Листинг 8.2. Суммирование элементов трех списков def func(e1, e2, e3):
""" Суммирование элементов трех разных списков """ return e1 + e2 + e3 # Возвращаем новое значение arr1 = [1, 2, 3, 4, 5] arr2 = [10, 20, 30, 40, 50] arr3 = [100, 200, 300, 400, 500] print( list( map(func, arr1, arr2, arr3) ) )
# Результат выполнения: [111, 222, 333, 444, 555]
Если количество элементов в последовательностях различается, за основу выбирается по- следовательность с минимальным количеством элементов (листинг 8.3).
Листинг 8.3. Суммирование элементов трех списков разной длины def func(e1, e2, e3):
""" Суммирование элементов трех разных списков """ return e1 + e2 + e3 arr1 = [1, 2, 3, 4, 5] arr2 = [10, 20] arr3 = [100, 200, 300, 400, 500] print( list( map(func, arr1, arr2, arr3) ) )
# Результат выполнения: [111, 222]
Встроенная функция zip()
на каждой итерации возвращает кортеж, содержащий элементы последовательностей, которые расположены на одинаковом смещении. Функция возвраща-
152
Часть I. Основы языка Python ет объект, поддерживающий итерации (а не список, как это было ранее в Python 2). Чтобы получить список в версии Python 3, необходимо результат передать в функцию list()
Формат функции: zip(<Последовательность1>[, ..., <ПоследовательностьN>])
Пример:
>>> zip([1, 2, 3], [4, 5, 6], [7, 8, 9])
>>> list(zip([1, 2, 3], [4, 5, 6], [7, 8, 9]))
[(1, 4, 7), (2, 5, 8), (3, 6, 9)]
Если количество элементов в последовательностях будет разным, то в результат попадут только элементы, которые существуют во всех последовательностях на одинаковом смеще- нии:
>>> list(zip([1, 2, 3], [4, 6], [7, 8, 9, 10]))
[(1, 4, 7), (2, 6, 8)]
В качестве еще одного примера переделаем нашу программу суммирования элементов трех списков (см. листинг 8.3) и используем функцию zip()
вместо функции map()
(листинг 8.4).
Листинг 8.4. Суммирование элементов трех списков с помощью функции zip() arr1 = [1, 2, 3, 4, 5] arr2 = [10, 20, 30, 40, 50] arr3 = [100, 200, 300, 400, 500] arr = [x + y + z for (x, y, z) in zip(arr1, arr2, arr3)] print(arr)
# Результат выполнения: [111, 222, 333, 444, 555]
Функция filter()
позволяет выполнить проверку элементов последовательности. Формат функции: filter(<Функция>, <Последовательность>)
Если в первом параметре вместо названия функции указать значение
None
, то каждый эле- мент последовательности будет проверен на соответствие значению
True
. Если элемент в логическом контексте возвращает значение
False
, то он не будет добавлен в возвращаемый результат. Функция возвращает объект, поддерживающий итерации (а не список или кор- теж, как это было ранее в Python 2). Чтобы получить список в версии Python 3, необходимо результат передать в функцию list()
:
>>> filter(None, [1, 0, None, [], 2])
>>> list(filter(None, [1, 0, None, [], 2]))
[1, 2]
Аналогичная операция с использованием генераторов списков выглядит так:
>>> [ i for i in [1, 0, None, [], 2] if i ]
[1, 2]
В первом параметре можно указать ссылку на функцию, в которую в качестве параметра будет передаваться текущий элемент последовательности. Если элемент нужно добавить
Глава 8. Списки, кортежи, множества и диапазоны
153 в возвращаемое функцией filter()
значение, то внутри функции, указанной в качестве первого параметра, следует вернуть значение
True
, в противном случае — значение
False
Для примера удалим все отрицательные значения из списка (листинг 8.5).
Листинг 8.5. Пример использования функции filter() def func(elem): return elem >= 0 arr = [-1, 2, -3, 4, 0, -20, 10] arr = list(filter(func, arr)) print(arr) # Результат: [2, 4, 0, 10]
# Использование генераторов списков arr = [-1, 2, -3, 4, 0, -20, 10] arr = [ i for i in arr if func(i) ] print(arr) # Результат: [2, 4, 0, 10]
Функция reduce()
из модуля functools применяет указанную функцию к парам элементов и накапливает результат. Функция имеет следующий формат: reduce(<Функция>, <Последовательность>[, <Начальное значение>])
В параметр
<Функция>
в качестве параметров передаются два элемента: первый элемент будет содержать результат предыдущих вычислений, а второй — значение текущего эле- мента. Получим сумму всех элементов списка (листинг 8.6).
Листинг 8.6. Пример использования функции reduce() from functools import reduce # Подключаем модуль def func(x, y): print("({0}, {1})".format(x, y), end=" ") return x + y arr = [1, 2, 3, 4, 5] summa = reduce(func, arr)
# Последовательность: (1, 2) (3, 3) (6, 4) (10, 5) print(summa) # Результат выполнения: 15 summa = reduce(func, arr, 10)
# Последовательность: (10, 1) (11, 2) (13, 3) (16, 4) (20, 5) print(summa) # Результат выполнения: 25 summa = reduce(func, [], 10) print(summa) # Результат выполнения: 10 8.7. Добавление и удаление элементов списка
Для добавления и удаления элементов списка используются следующие методы:
append(<Объект>)
— добавляет один объект в конец списка. Метод изменяет текущий список и ничего не возвращает:
154
Часть I. Основы языка Python
>>> arr = [1, 2, 3]
>>> arr.append(4); arr # Добавляем число
[1, 2, 3, 4]
>>> arr.append([5, 6]); arr # Добавляем список
[1, 2, 3, 4, [5, 6]]
>>> arr.append((7, 8)); arr # Добавляем кортеж
[1, 2, 3, 4, [5, 6], (7, 8)]
extend(<Последовательность>)
— добавляет элементы последовательности в конец списка. Метод изменяет текущий список и ничего не возвращает:
>>> arr = [1, 2, 3]
>>> arr.extend([4, 5, 6]) # Добавляем список
>>> arr.extend((7, 8, 9)) # Добавляем кортеж
>>> arr.extend("abc") # Добавляем буквы из строки
>>> arr
[1, 2, 3, 4, 5, 6, 7, 8, 9, 'a', 'b', 'c']
Добавить несколько элементов можно с помощью операции конкатенации или операто- ра
+=
:
>>> arr = [1, 2, 3]
>>> arr + [4, 5, 6] # Возвращает новый список
[1, 2, 3, 4, 5, 6]
>>> arr += [4, 5, 6] # Изменяет текущий список
>>> arr
[1, 2, 3, 4, 5, 6]
Кроме того, можно воспользоваться операцией присваивания значения срезу:
>>> arr = [1, 2, 3]
>>> arr[len(arr):] = [4, 5, 6] # Изменяет текущий список
>>> arr
[1, 2, 3, 4, 5, 6]
insert(<Индекс>, <Объект>)
— добавляет один объект в указанную позицию. Осталь- ные элементы смещаются. Метод изменяет текущий список и ничего не возвращает:
>>> arr = [1, 2, 3]
>>> arr.insert(0, 0); arr # Вставляем 0 в начало списка
[0, 1, 2, 3]
>>> arr.insert(-1, 20); arr # Можно указать отрицательные числа
[0, 1, 2, 20, 3]
>>> arr.insert(2, 100); arr # Вставляем 100 в позицию 2
[0, 1, 100, 2, 20, 3]
>>> arr.insert(10, [4, 5]); arr # Добавляем список
[0, 1, 100, 2, 20, 3, [4, 5]]
Метод insert()
позволяет добавить только один объект. Чтобы добавить несколько объектов, можно воспользоваться операцией присваивания значения срезу. Добавим несколько элементов в начало списка:
>>> arr = [1, 2, 3]
>>> arr[:0] = [-2, -1, 0]
>>> arr
[-2, -1, 0, 1, 2, 3]
Глава 8. Списки, кортежи, множества и диапазоны
155
pop([<Индекс>])
— удаляет элемент, расположенный по указанному индексу, и воз- вращает его. Если индекс не указан, то удаляет и возвращает последний элемент списка.
Если элемента с указанным индексом нет, или список пустой, возбуждается исключение
IndexError
:
>>> arr = [1, 2, 3, 4, 5]
>>> arr.pop() # Удаляем последний элемент списка
5
>>> arr # Список изменился
[1, 2, 3, 4]
>>> arr.pop(0) # Удаляем первый элемент списка
1
>>> arr # Список изменился
[2, 3, 4]
Удалить элемент списка позволяет также оператор del
:
>>> arr = [1, 2, 3, 4, 5]
>>> del arr[4]; arr # Удаляем последний элемент списка
[1, 2, 3, 4]
>>> del arr[:2]; arr # Удаляем первый и второй элементы
[3, 4]
remove(<Значение>)
— удаляет первый элемент, содержащий указанное значение. Если элемент не найден, возбуждается исключение
ValueError
. Метод изменяет текущий спи- сок и ничего не возвращает:
>>> arr = [1, 2, 3, 1, 1]
>>> arr.remove(1) # Удаляет только первый элемент
>>> arr
[2, 3, 1, 1]
>>> arr.remove(5) # Такого элемента нет
Traceback (most recent call last):
File "
", line 1, in
ValueError: list.remove(x): x not in list
clear()
— удаляет все элементы списка, очищая его. Никакого результата при этом не возвращается:
>>> arr = [1, 2, 3, 1, 1]
>>> arr.clear()
>>> arr
[]
Если необходимо удалить все повторяющиеся элементы списка, то можно преобразовать список во множество, а затем множество обратно преобразовать в список. Обратите внима- ние на то, что список должен содержать только неизменяемые объекты (например, числа, строки или кортежи). В противном случае возбуждается исключение
TypeError
:
>>> arr = [1, 2, 3, 1, 1, 2, 2, 3, 3]
>>> s = set(arr) # Преобразуем список во множество
>>> s
{1, 2, 3}
>>> arr = list(s) # Преобразуем множество в список
>>> arr # Все повторы были удалены
[1, 2, 3]
156
Часть I. Основы языка Python
8.8. Поиск элемента в списке и получение сведений о значениях, входящих в список
Как вы уже знаете, выполнить проверку на вхождение элемента в список позволяет опера- тор in
: если элемент входит в список, то возвращается значение
True
, в противном слу- чае —
False
. Аналогичный оператор not in выполняет проверку на невхождение элемента в список: если элемент отсутствует в списке, возвращается
True
, в противном случае —
False
:
>>> 2 in [1, 2, 3, 4, 5], 6 in [1, 2, 3, 4, 5] # Проверка на вхождение
(True, False)
>>> 2 not in [1, 2, 3, 4, 5], 6 not in [1, 2, 3, 4, 5] # Проверка на невхождение
(False, True)
Тем не менее оба этих оператора не дают никакой информации о местонахождении элемен- та внутри списка. Чтобы узнать индекс элемента внутри списка, следует воспользоваться методом index()
. Формат метода: index(<Значение>[, <Начало>[, <Конец>]])
Метод index()
возвращает индекс элемента, имеющего указанное значение. Если значение не входит в список, то возбуждается исключение
ValueError
. Если второй и третий пара- метры не указаны, поиск будет производиться с начала и до конца списка:
>>> arr = [1, 2, 1, 2, 1]
>>> arr.index(1), arr.index(2)
(0, 1)
>>> arr.index(1, 1), arr.index(1, 3, 5)
(2, 4)
>>> arr.index(3)
Traceback (most recent call last):
File "
", line 1, in
ValueError: 3 is not in list
Узнать общее количество элементов с указанным значением позволяет метод count(<Значение>)
. Если элемент не входит в список, возвращается значение
0
:
>>> arr = [1, 2, 1, 2, 1]
>>> arr.count(1), arr.count(2)
(3, 2)
>>> arr.count(3) # Элемент не входит в список
0
С помощью функций max()
и min()
можно узнать максимальное и минимальное значение из всех, что входят в список, соответственно:
>>> arr = [1, 2, 3, 4, 5]
>>> max(arr), min(arr)
(5, 1)
Функция any(<Последовательность>)
возвращает значение
True
, если в последовательности существует хотя бы один элемент, который в логическом контексте возвращает значение
True
. Если последовательность не содержит элементов, возвращается значение
False
:
>>> any([0, None]), any([0, None, 1]), any([])
(False, True, False)
Глава 8. Списки, кортежи, множества и диапазоны
157
Функция all(<Последовательность>)
возвращает значение
True
, если все элементы после- довательности в логическом контексте возвращают значение
True или последовательность не содержит элементов:
>>> all([0, None]), all([0, None, 1]), all([]), all(["str", 10])
(False, False, True, True)
8.9. Переворачивание и перемешивание списка
Метод reverse()
изменяет порядок следования элементов списка на противоположный.
Метод изменяет текущий список и ничего не возвращает:
>>> arr = [1, 2, 3, 4, 5]
>>> arr.reverse() # Изменяется текущий список
>>> arr
[5, 4, 3, 2, 1]
Если необходимо изменить порядок следования и получить новый список, следует восполь- зоваться функцией reversed(<Последовательность>)
. Она возвращает итератор, который можно преобразовать в список с помощью функции list()
или генератора списков:
>>> arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
>>> reversed(arr)
>>> list(reversed(arr)) # Использование функции list()
[10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
>>> for i in reversed(arr): print(i, end=" ") # Вывод с помощью цикла
10 9 8 7 6 5 4 3 2 1
>>> [i for i in reversed(arr)] # Использование генератора списков
[10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
Функция shuffle(<Список>[, <Число от 0.0 до 1.0>])
из модуля random перемешивает список случайным образом. Функция перемешивает сам список и ничего не возвращает.
Если второй параметр не указан, используется значение, возвращаемое функцией random()
:
>>> import random # Подключаем модуль random
>>> arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
>>> random.shuffle(arr) # Перемешиваем список случайным образом
>>> arr
[2, 7, 10, 4, 6, 8, 9, 3, 1, 5]
8.10. Выбор элементов случайным образом
Получить элементы из списка случайным образом позволяют следующие функции из моду- ля random
:
choice(<Последовательность>)
— возвращает случайный элемент из любой последова- тельности (строки, списка, кортежа):
>>> import random # Подключаем модуль random
>>> random.choice(["s", "t", "r"]) # Список 's'
158
Часть I. Основы языка Python
sample(<Последовательность>, <Количество элементов>)
— возвращает список из ука- занного количества элементов. В этот список попадут элементы из последовательности, выбранные случайным образом. В качестве последовательности можно указать любые объекты, поддерживающие итерации:
>>> arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
>>> random.sample(arr, 2)
[7, 10]
>>> arr # Сам список не изменяется
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
8.11. Сортировка списка
Отсортировать список позволяет метод sort()
. Он имеет следующий формат: sort([key=None][, reverse=False])
Все параметры не являются обязательными. Метод изменяет текущий список и ничего не возвращает. Отсортируем список по возрастанию с параметрами по умолчанию:
>>> arr = [2, 7, 10, 4, 6, 8, 9, 3, 1, 5]
>>> arr.sort() # Изменяет текущий список
>>> arr
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Чтобы отсортировать список по убыванию, следует в параметре reverse указать значение
True
:
>>> arr = [2, 7, 10, 4, 6, 8, 9, 3, 1, 5]
>>> arr.sort(reverse=True) # Сортировка по убыванию
>>> arr
[10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
Надо заметить, что стандартная сортировка зависит от регистра символов (листинг 8.7).
Листинг 8.7. Стандартная сортировка arr = ["единица1", "Единый", "Единица2"] arr.sort() for i in arr: print(i, end=" ")
# Результат выполнения: Единица2 Единый единица1
В параметре key метода sort()
можно указать функцию, выполняющую какое-либо дейст- вие над каждым элементом списка. В качестве единственного параметра она должна при- нимать значение очередного элемента списка, а в качестве результата — возвращать результат действий над ним. Этот результат будет участвовать в процессе сортировки, но значения самих элементов списка не изменятся.
Выполнив пример из листинга 8.7, мы получили неправильный результат сортировки, ведь
Единый и
Единица2
больше единица1
. Чтобы регистр символов не учитывался, в параметре key мы укажем функцию для изменения регистра символов (листинг 8.8).