Статью подготовили специалисты образовательного сервиса Zaochnik.
Многомерные списки в Python. Примеры обработки данных
- 21 января 2025
- 6 минут
- 49
Способы обработки и вывода вложенных списков
В большинстве задач необходимо хранить табличные данные, которые обычно представляются в виде матриц или двумерных массивов. В Python таблицу можно создать как список, в котором каждый элемент является отдельным списком.
Для создания числовой таблицы с двумя строками и тремя столбцами, можно записать так:
```
A = [[1, 2, 3], [4, 5, 6]]
```
Где `A[0]` - является первой строкой списка и содержит числа [1, 2, 3], что значит:
- `A[0][0] == 1`
- `A[0][1] == 2`
- `A[0][2] == 3`
А для второй строки:
- `A[1][0] == 4`
- `A[1][1] == 5`
- `A[1][2] == 6`
Обработка и вывод таких списков часто происходит с помощью вложенных циклов.
Для построчного вывода двумерного числового списка с разделением чисел пробелами можно использовать следующий код:
```
for i in range(len(A)):
for j in range(len(A[i])):
print(A[i][j], end=' ')
print()
```
Такой же вывод можно сделать, используя итерацию по элементам списка:
```
for row in A:
for elem in row:
print(elem, end=' ')
print()
```
Для вывода одной строки удобнее использовать метод `join`:
```
for row in A:
print(' '.join(map(str, row)))
```
Чтобы подсчитать сумму всех чисел в списке, также подойдут два вложенных цикла:
```
S = 0
for i in range(len(A)):
for j in range(len(A[i])):
S += A[i][j]
```
И аналогичный вариант без индексов:
```
S = 0
for row in A:
for elem in row:
S += elem
```
Создание двумерного списка
Задача
Предположим, нам даны два числа: с `n` количеством строк и `m` столбцов. Нужно создать список размером `n×m`, где все значения нули. На первый взгляд, может показаться, что простое решение не работает:
```
A = [[0] * m] * n
```
При присвоении `A[0][0] == 1`, произойдет изменение всех строк, так как они ссылаются на один и тот же список. Это происходит потому, что `[0] * m` возвращает ссылку на список из `m` нулей. При следующем повторении выводит список, все строки которого ссылаются на один и тот же оператор.
Решение
Первый вариант: сначала создаем список из `n` элементов (сперва это просто список из `n` нулей), а затем каждый элемент заменяем на другой одномерный список из `m` элементов:
```
A = [0] * n
for i in range(n):
A[i] = [0] * m
```
Второй вариант – создать пустой список и добавлять в него новый элемент в виде одномерного списка:
```
A = []
for i in range(n):
A.append([0] * m)
```
Однако наиболее лаконично можно использовать генератор, для создания списка из `n` элементов, при этом каждый из элемента будет являться списком, состоящим из `m` нулей:
```
A = [[0] * m for i in range(n)]
```
При этом все элементы создаются независимыми, и не происходит копирования ссылок на один и тот же список.
Ввод двумерного списка
Рассмотрим пример, когда программа получает на вход двумерный массив из `n` строк, где каждая строка содержит `m` чисел, разделенных пробелами. Реализовать это можно, например, так:
```
A = []
for i in range(n):
A.append(list(map(int, input().split())))
```
Сделаем то же самое, но не используя сложные вложенные случаи:
```
A = []
for i in range(n):
row = input().split()
for i in range(len(row)):
row[i] = int(row[i])
A.append(row)
```
Также возможно использовать генератор:
```
A = [list(map(int, input().split())) for i in range(n)]
```
Сложный пример обработки двумерной таблицы
Предположим, мы имеем квадратный массив с `n` строками и `n` столбцами. Нам нужно назначить значения элементам на главной диагонали, проходящей из верхнего левого угла в нижний правый. Элементам, расположенным выше, присваиваем значение 0, а ниже – значение 2. В результате получим (пример для `n=4`):
Чтобы решить эту задачу, мы можем использовать циклы. Элементы, находящиеся выше главной диагонали, определяются как `A[i][j]`, где `i < j`, а ниже – `i > j`. Это позволяет написать следующий алгоритм:
```
for i in range(n):
for j in range(n):
if i < j:
A[i][j] = 0
elif i > j:
A[i][j] = 2
else:
A[i][j] = 1
```
Однако такой алгоритм неэффективен, поскольку для каждого элемента выполняются условия `if`. Упростим алгоритм, сначала заполнив главную диагональ:
```
for i in range(n):
A[i][i] = 1
```
Затем назначим значение 0 всем элементам выше диагонали, используя вложенные циклы:
```
for i in range(n):
for j in range(i + 1, n):
A[i][j] = 0
```
И для элементов ниже диагонали:
```
for i in range(n):
for j in range(0, i):
A[i][j] = 2
```
Мы можем также объединить внешние циклы и написать решение в более компактном виде:
```
for i in range(n):
for j in range(0, i):
A[i][j] = 2
A[i][i] = 1
for j in range(i + 1, n):
A[i][j] = 0
```
Еще один способ — использовать операцию повторения для построения строки списка. В таком решении `i`-я строка будет состоять из `i` чисел 2, затем одного числа 1 и `(n-i-1)` чисел 0:
```
for i in range(n):
A[i] = [2] * i + [1] + [0] * (n - i - 1)
```
А теперь используем вместо цикла - генератор:
```
A = [[2] * i + [1] + [0] * (n - i - 1) for i in range(n)]
```