Аннотация. Урок посвящен работе с вложенными списками.
Для создания вложенного списка можно использовать литеральную форму записи – перечисление элементов через запятую в квадратных скобках:
my_list = [[0], [1, 2], [3, 4, 5]]
Иногда нужно создать вложенный список, заполненный по определенному правилу – шаблону. Например, список длиной n
, содержащий списки длиной m
, каждый из которых заполнен нулями.
Рассмотрим несколько способов решения задачи.
Способ 1. Создадим пустой список, потом n
раз добавим в него новый элемент – список длины m
, составленный из нулей:
n, m = int(input()), int(input()) # считываем значения n и m
my_list = []
for _ in range(n):
my_list.append([0] * m)
print(my_list)
Если ввести значения n = 3
, m = 5
, то результатом работы такого кода будет:
[[0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]]
Если передать значения n = 5
, m = 3
, то результатом работы такого кода будет:
[[0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]]
Способ 2. Сначала создадим список из n
элементов (для начала просто из n
нулей). Затем сделаем каждый элемент списка ссылкой на другой список из m
элементов, заполненный нулями:
n, m = int(input()), int(input()) # считываем значения n и m
my_list = [0] * n
for i in range(n):
my_list[i] = [0] * m
print(my_list)
Способ 3. Можно использовать генератор списка: создадим список из n
элементов, каждый из которых будет списком, состоящих из m
нулей:
n, m = int(input()), int(input()) # считываем значения n и m
my_list = [[0] * m for _ in range(n)]
print(my_list)
В этом случае каждый элемент создается независимо от остальных (заново конструируется вложенный список [0] * m
для заполнения очередного элемента списка).
Обратите внимание, что очевидное решение, использующее операцию умножения списка на число (операция повторения), оказывается неверным:
n, m = int(input()), int(input()) # считываем значения n и m
my_list = [[0] * m ] * n
print(my_list)
В этом легко убедиться, если присвоить элементу my_list[0][0]
любое значение, например, 17
, а затем вывести список на печать:
n, m = int(input()), int(input())
my_list = [[0] * m ] * n
my_list[0][0] = 17
print(my_list)
Если ввести значения n = 5
, m = 3
, то результатом работы такого кода будет:
[[17, 0, 0], [17, 0, 0], [17, 0, 0], [17, 0, 0], [17, 0, 0]]
То есть, изменив значение элемента списка my_list[0][0]
, мы также изменили значения элементов my_list[1][0]
, my_list[2][0]
, my_list[3][0]
, my_list[4][0]
.
Причина такого поведения кроется в самой природе списков (тип list
). В Python списки – ссылочный тип данных. Конструкция [0] * m
возвращает ccылку на список из m
нулей. Повторение этого элемента создает список из n
ссылок на один и тот же список.
Вложенный список нельзя создать при помощи операции повторения (умножения списка на число). Для корректного создания вложенного списка мы используем способы 1−31-3, отдавая предпочтение способу 33.
Если элементы списка вводятся через клавиатуру (каждая строка на отдельной строке, всего n
строк, числа в строке разделяются пробелами), для ввода списка можно использовать следующий код:
n = 4 # количество строк (элементов)
my_list = []
for _ in range(n):
elem = [int(i) for i in input().split()] # создаем список из элементов строки
my_list.append(elem)
В этом примере мы используем списочный метод append()
, передавая ему в качестве аргумента другой список. Так у нас получается список списков.
В результате, если на вход программе подаются строки:
2 4
6 7 8 9
1 3
5 6 5 4 3 1
то в переменной my_list
будет храниться список:
[[2, 4], [6, 7, 8, 9], [1, 3], [5, 6, 5, 4, 3, 1]]
Не забывайте, что метод split()
возвращает список строк, а не чисел. Поэтому мы предварительно сконвертировали строку в число, с помощью вызова функции int()
.
Также следует помнить отличие работы списочных методов append()
и extend()
.
Следующий код:
n = 4
my_list = []
for _ in range(n):
elem = [int(i) for i in input().split()]
my_list.extend(elem)
создает одномерный (!) список, а не вложенный. В переменной my_list
будет храниться список:
[2, 4, 6, 7, 8, 9, 1, 3, 5, 6, 5, 4, 3, 1]
Как мы уже знаем, для доступа к элементу списка указывают индекс этого элемента в квадратных скобках. В случае двумерных вложенных списков надо указать два индекса (каждый в отдельных квадратных скобках), в случае трехмерного списка — три индекса и т. д.
Рассмотрим программный код:
my_list = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
print(my_list[0][0])
print(my_list[1][2])
print(my_list[2][1])
Результатом работы такого кода будет:
1
6
8
Когда нужно перебрать все элементы вложенного списка (например, чтобы вывести их на экран), обычно используются вложенные циклы.
Рассмотрим программный код:
my_list = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
for i in range(len(my_list)):
for j in range(len(my_list[i])):
print(my_list[i][j], end=' ') # используем необязательный параметр end
print() # перенос на новую строку
Результатом работы такого кода будет:
1 2 3
4 5 6
7 8 9
Вызов функции print()
с пустыми параметрами нужен для того, чтобы переносить вывод на новую строку, после того как будет распечатан очередной элемент (список) вложенного списка.
В предыдущем примере мы перебирали индексы элементов, а можно сразу перебирать сами элементы вложенного списка:
my_list = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
for row in my_list:
for elem in row:
print(elem, end=' ')
print()
Результатом работы такого кода будет:
1 2 3
4 5 6
7 8 9
Перебор элементов вложенного списка по индексам дает нам больше гибкости для вывода данных. Например, поменяв порядок переменных i
и j
, мы получаем иной тип вывода:
my_list = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
for i in range(len(my_list)):
for j in range(len(my_list[i])):
print(my_list[j][i], end=' ') # выводим my_list[j][i] вместо my_list[i][j]
print()
Результатом работы такого кода будет:
1 4 7
2 5 8
3 6 9
Для обработки элементов вложенного списка, так же как и для вывода его элементов на экран, как правило, используются вложенные циклы.
Используем вложенный цикл для подсчета суммы всех чисел в списке:
my_list = [[1, 9, 8, 7, 4], [7, 3, 4], [2, 1]]
total = 0
for i in range(len(my_list)):
for j in range(len(my_list[i])):
total += my_list[i][j]
print(total)
Или то же самое с циклом не по индексу, а по значениям:
my_list = [[1, 9, 8, 7, 4], [7, 3, 4], [2, 1]]
total = 0
for row in my_list:
for elem in row:
total += elem
print(total)
Таким образом, можно обработать элементы вложенного списка практически в любом языке программирования. В Python, однако, можно упростить код, если использовать встроенную функцию sum()
, которая принимает список чисел и возвращает его сумму. Подсчет суммы с помощью функции sum()
выглядит так:
my_list = [[1, 9, 8, 7, 4], [7, 3, 4], [2, 1]]
total = 0
for row in my_list: # в один цикл
total += sum(row)
print(total)
Названия переменных row
(строка) и elem
(элемент) удобно использовать при переборе вложенного списка по значениям. Названия переменных i
и j
используются при переборе вложенного списка по индексам.