- 6 августа 2025
- 9 минут
- 571
Матрицы в Python: создание вложенных списков и использование вложенных генераторов
Статью подготовили специалисты образовательного сервиса Zaochnik.
Понятие и создание матриц
При решении различных задач часто требуется хранить данные в табличном формате, который принято называть матрицей или двумерным массивом. В Python этот формат можно представить как список, состоящий из строк, где каждый элемент также является списком, например, чисел.
Создать числовую матрицу с двумя строками и тремя столбцами можно следующим образом:
```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`.
Для вывода и обработки такого списка обычно происходит с помощью двух вложенных циклов. Где первый проходит по строкам, а второй — по элементам внутри каждой строки.
Для вывода двумерного числового списка по строкам, разделяя элементы пробелами, можно воспользоваться следующим кодом:
```python
for i in range(len(A)):
for j in range(len(A[i])):
print(A[i][j], end=' ')
print()
```
Есть и альтернативный подход — использовать циклы по элементам списка, а не по индексам:
```python
for row in A:
for elem in row:
print(elem, end=' ')
print()
```
Для удобного вывода одной строки с использованием метода `join`, можно применить следующий код:
```python
for row in A:
print(' '.join(map(str, row)))
```
Если необходимо подсчитать сумму всех чисел в списке, то также можно воспользоваться двумя вложенными циклами:
```python
Sum = 0
for i in range(len(A)):
for j in range(len(A[i])):
Sum += A[i][j]
```
Однако можно использовать и другой подход, проходя непосредственно по строкам:
```python
Sum = 0
for row in A:
for elem in row:
Sum += elem
```
Создание вложенных списков
Предположим, у вас есть два значения `n` и `m`, где:
- `n` - количество строк
- `m` - количество столбцов.
Нужно создать список размером `n×m`, заполненный нулями. На первый взгляд, кажется, что следующий код будет верным:
```python
! Неправильно
A = [[0] * m] * n
```
Тем не менее, если вы установите значение `A[0][0]` равным `1`, и затем выведете `A[1][0]`, то получите также `1`. Это происходит, поскольку ` [0] * m` создает ссылку на один и тот же список из `m` нулей. Повторяя этот элемент, мы создаем массив из `n` компонентов, которые указывают на один и тот же список.
Поэтому двумерный список нельзя корректно создать с помощью операции повторения одной строки.
Первый способ решения - сначала создаем список из `n` элементов, который изначально состоит из нулей, а затем присваиваем каждому элементу ссылку на одномерный список из `m` элементов:
```python
A = [0] * n
for i in range(n):
A[i] = [0] * m
```
Альтернативный метод — создать пустой список и добавлять в него новый элемент, представляющий собой строку, `n` раз:
```python
A = []
for i in range(n):
A.append([0] * m)
```
Наиболее простое решение - использовать генератор, чтобы создать список из `n` элементов, каждый из которых является списком из `m` значений (в нашем примере - нулей):
```python
A = [[0] * m for i in range(n)]
```
При таком способе каждый элемент формируется отдельно, что исключает копирование ссылок на один и тот же список.
Ввод двумерного массива
В случае, когда программа получает на вход двумерный массив вида - `n` строк, каждая в отдельности содержит `m` чисел, разделенных пробелами, - то считывание этих данных можно осуществить следующим образом:
```python
A = []
for i in range(n):
A.append(list(map(int, input().split())))
```
Либо, чтобы избежать сложных вложенных вызовов, можно сделать так:
```python
A = []
for i in range(n):
row = input().split()
for j in range(len(row)):
row[j] = int(row[j])
A.append(row)
```
Допустимо воспользоваться генератором для выполнения данной задачи:
```python
A = [list(map(int, input().split())) for i in range(n)]
```
Обработка двумерного массива
Представим, что у нас есть квадратный массив размером `n×n`. Необходимо тем элементам, которые расположены
- на главной диагонали (от верхнего левого к нижнему правому углу), присвоить значение `1`;
- элементам выше диагонали — `0`;
- а элементам ниже — `2`.
Это приведет к следующему массиву (пример в случае `n = 4`):
```
1 0 0 0
2 1 0 0
2 2 1 0
2 2 2 1
```
Можем рассмотреть некоторые из вариантов решения для этой задачи. Элементы, расположенные выше главной диагонали соответствуют условию `A[i][j]`, где `i < j`, а элементы ниже — где `i > j`. Мы можем сравнивать индексы `i` и `j`, чтобы определить, какое значение следует присвоить `A[i][j]`:
```python
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` для каждого элемента. Упрощая алгоритм, можем сразу заполнить главную диагональ одним циклом:
```python
for i in range(n):
A[i][i] = 1
```
После присвоения значения единицы элементам главной диагонали, следующим шагом будет заполнение всех элементов выше этой диагонали нулями. Для этого в каждой строке с номером `i` необходимо установить значение для элементов `A[i][j]`, где `j` варьируется от `i + 1` до `n - 1`. Это можно сделать с помощью вложенных циклов:
```python
for i in range(n):
for j in range(i + 1, n):
A[i][j] = 0
```
Подобным образом присвоим значение `2` элементам `A[i][j]` для `j` в диапазоне `0` до `i-1`:
```python
for i in range(n):
for j in range(0, i):
A[i][j] = 2
```
Лучше всего объединить внешние циклы в один, с целью получить более компактное решение:
```python
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` нулей:
```python
for i in range(n):
A[i] = [2] * i + [1] + [0] * (n - i - 1)
```
Или заменив цикл на генератор:
```python
A = [[2] * i + [1] + [0] * (n - i - 1) for i in range(n)]
```
Вложенные генераторы для двумерных массивов
Создавая двумерные массивы, также можно применять вложенные генераторы.
Для создания списка из `n` строк и `m` столбцов можно использовать метод, который позволяет генерировать список из `n` элементов, каждый из которых представляет собой список из `m` нулей:
```python
[[0] * m for i in range(n)]
```
А вот создание внутреннего списка можно произвести с помощью генератора, например: `[0 for j in range(m)]`. Объединив два генератора, мы получаем вложенные генераторы:
```python
[[0 for j in range(m)] for i in range(n)]
```
Если вместо нуля подставить выражение, зависящее от `i` (индекса строки) и `j` (индекса столбца), это позволит сформировать массив, заполненный по определенной формуле.
Рассмотрим пример создания следующего массива, где между значениями добавлены пробелы для удобства отображения:
0 0 0 0 0 0
0 1 2 3 4 5
0 2 4 6 8 10
0 3 6 9 12 15
0 4 8 12 16 20
В таком примере имеется `n = 5` строк и `m = 6` столбцов, а значение элемента в строке `i` и столбце `j` подсчитывается используя формулу: `A[i][j] = i * j`.
Чтобы создать подобный массив можно использовать следующий генератор:
```python
[[i * j for j in range(m)] for i in range(n)]
```
Этот код эффективно создает двумерный массив, заполняя его значениями согласно заданной формуле.