Что такое двумерные массивы и где они используются
Двумерный массив — это структура данных, которая хранит элементы в виде таблицы с строками и столбцами. Представь себе обычную таблицу Excel или шахматную доску — вот так выглядит двумерный массив.
В Python двумерные массивы чаще всего создаются как списки списков — то есть каждый элемент главного списка сам является списком. Например:
matrix = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
]
Здесь у нас матрица 3×3: три строки и три столбца.
Где применяются двумерные массивы:
- Игры — игровые поля (шахматы, крестики-нолики, сапёр)
- Обработка изображений — пиксели картинки хранятся как двумерный массив
- Математика — матрицы для решения уравнений
- Таблицы данных — работа с табличными данными (расписание, оценки)
- Графы — матрица смежности для представления связей
Основы списков в Python
Прежде чем погрузиться в двумерные массивы, важно понять, как работают обычные (одномерные) списки.
Список — это изменяемая коллекция элементов, которые могут быть разных типов. Создаётся список так:
numbers = [1, 2, 3, 4, 5]
names = ["Аня", "Боря", "Вика"]
mixed = [1, "текст", 3.14, True]
Основные операции со списками:
- Доступ по индексу:
numbers[0]вернёт первый элемент (индексы начинаются с 0) - Изменение элемента:
numbers[2] = 10заменит третий элемент - Длина списка:
len(numbers)вернёт количество элементов - Добавление:
numbers.append(6)добавит элемент в конец
Двумерный массив — это просто список, где каждый элемент сам является списком. Поэтому все принципы работы со списками применимы и к двумерным массивам.
Создание двумерных массивов
Самый простой способ создать двумерный массив — написать список списков вручную:
# Матрица 2×3 (2 строки, 3 столбца)
matrix = [
[1, 2, 3],
[4, 5, 6]
]
# Игровое поле крестиков-ноликов 3×3
field = [
[".", ".", "."],
[".", "X", "."],
[".", ".", "O"]
]
Каждая строка — это отдельный список внутри главного списка. Количество строк определяется количеством внутренних списков, а количество столбцов — количеством элементов в каждой строке.
Важно: В Python нет требования, чтобы все строки имели одинаковую длину. Можно создать «неровный» массив, но это может привести к ошибкам. Старайся делать все строки одной длины.
Способы создания: циклы, умножение списков, генераторы
Метод 1: Вложенные циклы
Когда нужно создать большой массив, удобно использовать циклы:
# Создаём матрицу 4×5, заполненную нулями
rows = 4
cols = 5
matrix = []
for i in range(rows):
row = []
for j in range(cols):
row.append(0)
matrix.append(row)
# Результат: [[0,0,0,0,0], [0,0,0,0,0], [0,0,0,0,0], [0,0,0,0,0]]
Метод 2: Умножение списков (ОСТОРОЖНО!)
Можно попробовать создать массив умножением:
# НЕПРАВИЛЬНЫЙ способ!
matrix = [[0] * 3] * 3
Опасность! Этот код создаст массив, где все три строки — это один и тот же объект. Если изменишь элемент в одной строке, он изменится во всех:
matrix[0][0] = 5
# Теперь matrix = [[5,0,0], [5,0,0], [5,0,0]]
Это частая ошибка начинающих!
Правильный способ с умножением:
# Создаём каждую строку отдельно
matrix = [[0] * 3 for i in range(3)]
Метод 3: Генераторы списков
Самый «питоновский» и компактный способ — генераторы списков:
# Матрица 3×4, заполненная нулями
matrix = [[0 for j in range(4)] for i in range(3)]
# Матрица с номерами элементов
matrix = [[i * 4 + j for j in range(4)] for i in range(3)]
# [[0,1,2,3], [4,5,6,7], [8,9,10,11]]
# Единичная матрица (1 на диагонали, 0 в остальных местах)
n = 4
identity = [[1 if i == j else 0 for j in range(n)] for i in range(n)]
Совет: Генераторы списков быстрее работают, чем обычные циклы, и код получается короче. Используй их, когда освоишься с синтаксисом!
Доступ к элементам массива (индексация)
Чтобы получить доступ к элементу двумерного массива, используй двойную индексацию:
matrix = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
]
# Доступ к элементу
element = matrix[1][2] # 6 (вторая строка, третий столбец)
# Помни: индексы начинаются с 0!
first = matrix[0][0] # 1 (первая строка, первый столбец)
last = matrix[2][2] # 9 (третья строка, третий столбец)
Формат: matrix[i][j], где:
- i — номер строки (от 0 до количества строк - 1)
- j — номер столбца (от 0 до количества столбцов - 1)
Изменение элементов работает так же:
matrix[1][1] = 100 # Заменяем 5 на 100
# Теперь matrix = [[1,2,3], [4,100,6], [7,8,9]]
Можно получить целую строку:
second_row = matrix[1] # [4, 100, 6]
Для получения столбца нужен цикл или генератор:
# Второй столбец (индекс 1)
second_column = [row[1] for row in matrix] # [2, 100, 8]
Ввод двумерных массивов с клавиатуры
В задачах часто нужно считать массив с клавиатуры. Вот стандартные способы:
Способ 1: Построчный ввод
# Вводим размеры
rows = int(input("Количество строк: "))
cols = int(input("Количество столбцов: "))
# Создаём пустой массив
matrix = []
# Вводим каждую строку
print("Введите элементы построчно через пробел:")
for i in range(rows):
row = list(map(int, input().split()))
matrix.append(row)
Пример работы:
Количество строк: 2
Количество столбцов: 3
Введите элементы построчно через пробел:
1 2 3
4 5 6
Способ 2: С генератором списков
rows = int(input())
matrix = [list(map(int, input().split())) for _ in range(rows)]
Способ 3: Поэлементный ввод
rows, cols = 3, 3
matrix = [[0] * cols for _ in range(rows)]
print("Введите элементы:")
for i in range(rows):
for j in range(cols):
matrix[i][j] = int(input(f"Элемент [{i}][{j}]: "))
Задача: Ввести квадратную матрицу размером n×n.
n = int(input("Размер матрицы: "))
matrix = []
for i in range(n):
row = list(map(int, input().split()))
matrix.append(row)
print("Ваша матрица:", matrix)
Вывод двумерных массивов (форматирование)
Красивый вывод массива важен для читаемости результата.
Простой вывод
matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
# Вывод списком
print(matrix) # [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
Вывод построчно
# Каждая строка на новой строке
for row in matrix:
print(row)
# Вывод:
# [1, 2, 3]
# [4, 5, 6]
# [7, 8, 9]
Вывод в виде таблицы
# Элементы через пробел
for row in matrix:
for element in row:
print(element, end=" ")
print() # Переход на новую строку
# Вывод:
# 1 2 3
# 4 5 6
# 7 8 9
Форматированный вывод (ровные столбцы)
# Для чисел разной длины
matrix = [[1, 20, 300], [4, 50, 600], [7, 80, 900]]
for row in matrix:
for element in row:
print(f"{element:4}", end=" ") # 4 символа на элемент
print()
# Вывод:
# 1 20 300
# 4 50 600
# 7 80 900
Вывод одной строкой
# Через join
for row in matrix:
print(" ".join(map(str, row)))
Обработка массивов вложенными циклами
Вложенные циклы — основной инструмент для работы с двумерными массивами. Внешний цикл проходит по строкам, внутренний — по столбцам.
Базовый шаблон
matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
# Проход по всем элементам
for i in range(len(matrix)): # По строкам
for j in range(len(matrix[i])): # По столбцам
print(f"matrix[{i}][{j}] = {matrix[i][j]}")
Пример: Сумма всех элементов
total = 0
for i in range(len(matrix)):
for j in range(len(matrix[i])):
total += matrix[i][j]
print("Сумма:", total) # 45
Короткий вариант:
total = sum(sum(row) for row in matrix)
Пример: Поиск максимального элемента
max_value = matrix[0][0]
max_i, max_j = 0, 0
for i in range(len(matrix)):
for j in range(len(matrix[i])):
if matrix[i][j] > max_value:
max_value = matrix[i][j]
max_i, max_j = i, j
print(f"Максимум {max_value} на позиции [{max_i}][{max_j}]")
Пример: Замена элементов
# Удвоить все элементы
for i in range(len(matrix)):
for j in range(len(matrix[i])):
matrix[i][j] *= 2
Совет: Если не нужны индексы, используй более читаемый вариант:
for row in matrix:
for element in row:
print(element)
Операции с массивами (сортировка, поиск, изменение)
Сортировка строк
matrix = [[3, 1, 2], [6, 4, 5], [9, 7, 8]]
# Сортировка каждой строки
for row in matrix:
row.sort()
print(matrix) # [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
Сортировка всего массива по первому элементу строки
matrix = [[3, 1], [1, 5], [2, 3]]
matrix.sort() # Сортирует по первому элементу каждой строки
print(matrix) # [[1, 5], [2, 3], [3, 1]]
Сортировка по сумме элементов строки
matrix = [[3, 1], [1, 5], [2, 3]]
matrix.sort(key=sum)
print(matrix) # [[3, 1], [2, 3], [1, 5]]
Поиск элемента
def find_element(matrix, target):
for i in range(len(matrix)):
for j in range(len(matrix[i])):
if matrix[i][j] == target:
return (i, j)
return None
position = find_element(matrix, 5)
if position:
print(f"Найдено на позиции {position}")
else:
print("Не найдено")
Подсчёт элементов по условию
# Сколько элементов больше 5
matrix = [[1, 8, 3], [4, 9, 6], [7, 2, 5]]
count = 0
for row in matrix:
for element in row:
if element > 5:
count += 1
print(f"Элементов больше 5: {count}") # 4
# Короткий вариант
count = sum(1 for row in matrix for element in row if element > 5)
Добавление и удаление строк
matrix = [[1, 2, 3], [4, 5, 6]]
# Добавить новую строку
matrix.append([7, 8, 9])
# Удалить вторую строку (индекс 1)
del matrix[1]
# Вставить строку на позицию 1
matrix.insert(1, [10, 11, 12])
Работа с элементами по диагоналям
В квадратных матрицах часто нужно работать с диагональными элементами.
Главная диагональ
Главная диагональ идёт из левого верхнего угла в правый нижний. У элементов на главной диагонали i = j.
n = 4
matrix = [[i * n + j for j in range(n)] for i in range(n)]
# Вывод главной диагонали
print("Главная диагональ:")
for i in range(n):
print(matrix[i][i], end=" ") # 0 5 10 15
# Сумма элементов главной диагонали
diagonal_sum = sum(matrix[i][i] for i in range(n))
Побочная диагональ
Побочная диагональ идёт из правого верхнего угла в левый нижний. У элементов на побочной диагонали i + j = n - 1.
print("Побочная диагональ:")
for i in range(n):
j = n - 1 - i
print(matrix[i][j], end=" ") # 3 6 9 12
# Сумма побочной диагонали
side_diagonal_sum = sum(matrix[i][n - 1 - i] for i in range(n))
Замена диагоналей
# Заменить главную диагональ на нули
for i in range(n):
matrix[i][i] = 0
# Поменять диагонали местами
for i in range(n):
matrix[i][i], matrix[i][n - 1 - i] = matrix[i][n - 1 - i], matrix[i][i]
Задача: Проверить, является ли матрица симметричной относительно главной диагонали.
def is_symmetric(matrix):
n = len(matrix)
for i in range(n):
for j in range(n):
if matrix[i][j] != matrix[j][i]:
return False
return True
matrix = [[1, 2, 3], [2, 5, 6], [3, 6, 9]]
print(is_symmetric(matrix)) # True
Генераторы двумерных массивов
Генераторы списков позволяют создавать сложные массивы одной строкой кода.
Базовые примеры
# Таблица умножения
n = 5
multiplication_table = [[(i + 1) * (j + 1) for j in range(n)] for i in range(n)]
# Шахматная доска (0 и 1 чередуются)
board = [[(i + j) % 2 for j in range(8)] for i in range(8)]
# Матрица с случайными числами
import random
matrix = [[random.randint(1, 100) for j in range(5)] for i in range(5)]
Генераторы с условиями
# Только чётные числа
matrix = [[j if j % 2 == 0 else 0 for j in range(10)] for i in range(5)]
# Треугольная матрица (нули выше главной диагонали)
n = 4
triangular = [[j + 1 if j <= i else 0 for j in range(n)] for i in range(n)]
# [[1,0,0,0], [1,2,0,0], [1,2,3,0], [1,2,3,4]]
Вложенные генераторы для фильтрации
matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
# Получить все чётные элементы
evens = [element for row in matrix for element in row if element % 2 == 0]
# [2, 4, 6, 8]
# Преобразовать все элементы
squared = [[element ** 2 for element in row] for row in matrix]
# [[1,4,9], [16,25,36], [49,64,81]]
Работа с NumPy для больших массивов
Для работы с большими массивами и математическими операциями используй библиотеку NumPy. Она работает в разы быстрее обычных списков.
Установка NumPy
pip install numpy
Создание массивов NumPy
import numpy as np
# Из обычного списка
matrix = np.array([[1, 2, 3], [4, 5, 6]])
# Матрица из нулей
zeros = np.zeros((3, 4)) # 3 строки, 4 столбца
# Матрица из единиц
ones = np.ones((2, 5))
# Единичная матрица
identity = np.eye(4)
# Случайные числа от 0 до 1
random_matrix = np.random.random((3, 3))
# Случайные целые числа
random_int = np.random.randint(1, 100, (4, 4))
# Диапазон значений в матрице
range_matrix = np.arange(12).reshape(3, 4) # От 0 до 11 в форме 3×4
Доступ к элементам
matrix = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
# Элемент
element = matrix[1, 2] # 6 (в NumPy можно использовать запятую)
# Строка
row = matrix[1] # [4, 5, 6]
# Столбец
column = matrix[:, 1] # [2, 5, 8]
# Срез (подматрица)
submatrix = matrix[0:2, 1:3] # [[2,3], [5,6]]
Сравнение производительности
| Операция | Списки Python | NumPy |
|---|---|---|
| Создание массива 1000×1000 | ~100 мс | ~1 мс |
| Сумма элементов | ~50 мс | ~0.5 мс |
| Умножение на число | ~80 мс | ~0.3 мс |
| Поэлементное умножение | ~120 мс | ~0.4 мс |
Когда использовать NumPy:
- Массивы больше 100×100 элементов
- Математические операции с матрицами
- Научные расчёты и анализ данных
- Машинное обучение и нейросети
Когда достаточно обычных списков:
- Маленькие массивы (до 50×50)
- Учебные задачи и олимпиады
- Когда не нужны сложные вычисления
Операции с матрицами через NumPy
Арифметические операции
import numpy as np
a = np.array([[1, 2], [3, 4]])
b = np.array([[5, 6], [7, 8]])
# Поэлементное сложение
c = a + b # [[6,8], [10,12]]
# Поэлементное вычитание
d = a - b # [[-4,-4], [-4,-4]]
# Поэлементное умножение
e = a * b # [[5,12], [21,32]]
# Матричное умножение
f = np.dot(a, b) # [[19,22], [43,50]]
# или
f = a @ b # Тот же результат
Матричные операции
# Транспонирование
a_t = a.T # [[1,3], [2,4]]
# Определитель
det = np.linalg.det(a) # -2.0
# Обратная матрица
inv = np.linalg.inv(a)
# След матрицы (сумма диагонали)
trace = np.trace(a) # 5
# Ранг матрицы
rank = np.linalg.matrix_rank(a)
Агрегатные функции
matrix = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
# Сумма всех элементов
total = np.sum(matrix) # 45
# Сумма по строкам
row_sum = np.sum(matrix, axis=1) # [6, 15, 24]
# Сумма по столбцам
col_sum = np.sum(matrix, axis=0) # [12, 15, 18]
# Среднее значение
mean = np.mean(matrix) # 5.0
# Максимум и минимум
max_val = np.max(matrix) # 9
min_val = np.min(matrix) # 1
# Индекс максимума (в одномерном представлении)
max_index = np.argmax(matrix) # 8
Изменение формы массива
# Одномерный массив в двумерный
arr = np.arange(12)
matrix = arr.reshape(3, 4) # 3×4
# Двумерный в одномерный
flat = matrix.flatten() # [0,1,2,3,4,5,6,7,8,9,10,11]
# Изменить размер с сохранением данных
resized = matrix.reshape(2, 6) # 2×6
Практические примеры и задачи
Задача 1: Поворот матрицы на 90° по часовой стрелке
def rotate_90(matrix):
n = len(matrix)
# Создаём новую матрицу
rotated = [[0] * n for _ in range(n)]
for i in range(n):
for j in range(n):
rotated[j][n - 1 - i] = matrix[i][j]
return rotated
matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
result = rotate_90(matrix)
# [[7,4,1], [8,5,2], [9,6,3]]
Задача 2: Спиральный обход матрицы
def spiral_order(matrix):
result = []
while matrix:
# Берём первую строку
result += matrix.pop(0)
# Берём последние элементы оставшихся строк
if matrix and matrix[0]:
for row in matrix:
result.append(row.pop())
# Берём последнюю строку в обратном порядке
if matrix:
result += matrix.pop()[::-1]
# Берём первые элементы оставшихся строк снизу вверх
if matrix and matrix[0]:
for row in matrix[::-1]:
result.append(row.pop(0))
return result
matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
print(spiral_order(matrix)) # [1,2,3,6,9,8,7,4,5]
Задача 3: Игра «Жизнь» (одна итерация)
def count_neighbors(field, i, j):
rows, cols = len(field), len(field[0])
count = 0
for di in [-1, 0, 1]:
for dj in [-1, 0, 1]:
if di == 0 and dj == 0:
continue
ni, nj = i + di, j + dj
if 0 <= ni < rows and 0 <= nj < cols:
count += field[ni][nj]
return count
def next_generation(field):
rows, cols = len(field), len(field[0])
new_field = [[0] * cols for _ in range(rows)]
for i in range(rows):
for j in range(cols):
neighbors = count_neighbors(field, i, j)
if field[i][j] == 1: # Живая клетка
if neighbors in [2, 3]:
new_field[i][j] = 1
else: # Мёртвая клетка
if neighbors == 3:
new_field[i][j] = 1
return new_field
Задача 4: Поиск пути в лабиринте
def find_path(maze, start, end):
rows, cols = len(maze), len(maze[0])
visited = [[False] * cols for _ in range(rows)]
def dfs(i, j):
if i < 0 or i >= rows or j < 0 or j >= cols:
return False
if maze[i][j] == 1 or visited[i][j]: # Стена или уже были
return False
if (i, j) == end:
return True
visited[i][j] = True
# Проверяем 4 направления
if (dfs(i+1, j) or dfs(i-1, j) or
dfs(i, j+1) or dfs(i, j-1)):
return True
return False
return dfs(start[0], start[1])
# 0 - проход, 1 - стена
maze = [
[0, 1, 0, 0],
[0, 1, 0, 1],
[0, 0, 0, 1],
[1, 1, 0, 0]
]
print(find_path(maze, (0, 0), (3, 3))) # True
Оптимизация и производительность
Советы по оптимизации
1. Используй генераторы вместо циклов
# Медленно
matrix = []
for i in range(1000):
row = []
for j in range(1000):
row.append(0)
matrix.append(row)
# Быстрее
matrix = [[0 for j in range(1000)] for i in range(1000)]
# Ещё быстрее для больших массивов
import numpy as np
matrix = np.zeros((1000, 1000))
2. Избегай множественных проверок длины
# Неэффективно
for i in range(len(matrix)):
for j in range(len(matrix[i])):
process(matrix[i][j])
# Лучше
rows = len(matrix)
cols = len(matrix[0])
for i in range(rows):
for j in range(cols):
process(matrix[i][j])
3. Используй встроенные функции
# Медленно
total = 0
for row in matrix:
for element in row:
total += element
# Быстро
total = sum(sum(row) for row in matrix)
# С NumPy — ещё быстрее
import numpy as np
total = np.sum(matrix)
Сравнение подходов
Рекомендации по выбору структуры:
- Списки списков: для учебных задач, маленьких массивов, когда нужна гибкость
- NumPy: для больших массивов, математических вычислений, анализа данных
- Генераторы: когда массив используется один раз (экономия памяти)
Распространённые ошибки и как их избежать
Ошибка 1: Дублирование ссылок при создании
# НЕПРАВИЛЬНО!
matrix = [[0] * 3] * 3
matrix[0][0] = 5
# Результат: [[5,0,0], [5,0,0], [5,0,0]]
# ПРАВИЛЬНО
matrix = [[0] * 3 for _ in range(3)]
matrix[0][0] = 5
# Результат: [[5,0,0], [0,0,0], [0,0,0]]
Почему так происходит? При умножении [[0] * 3] * 3 создаётся три ссылки на один и тот же список, а не три разных списка. Изменение одного меняет все.
Ошибка 2: Выход за границы массива
matrix = [[1, 2, 3], [4, 5, 6]]
# Ошибка IndexError
# element = matrix[2][0] # Нет третьей строки!
# Безопасный доступ
if 0 <= i < len(matrix) and 0 <= j < len(matrix[0]):
element = matrix[i][j]
else:
print("Индекс вне границ")
Ошибка 3: Неровные строки
matrix = [[1, 2, 3], [4, 5], [6, 7, 8, 9]]
# Опасно!
# for i in range(len(matrix)):
# for j in range(len(matrix[0])): # matrix[0] имеет 3 элемента
# print(matrix[i][j]) # Ошибка на второй строке!
# Правильно
for i in range(len(matrix)):
for j in range(len(matrix[i])): # Длина текущей строки
print(matrix[i][j])
Ошибка 4: Изменение массива во время итерации
# Опасно!
for row in matrix:
if sum(row) == 0:
matrix.remove(row) # Изменяем массив во время обхода!
# Правильно — итерируемся по копии или индексам
for row in matrix[:]: # Копия массива
if sum(row) == 0:
matrix.remove(row)
# Или с индексами в обратном порядке
for i in range(len(matrix) - 1, -1, -1):
if sum(matrix[i]) == 0:
del matrix[i]
Ошибка 5: Неверное копирование
matrix = [[1, 2], [3, 4]]
# НЕПРАВИЛЬНО — копируется только ссылка
copy1 = matrix
copy1[0][0] = 100 # Изменяет и matrix!
# ПРАВИЛЬНО — поверхностная копия
copy2 = matrix.copy() # Или matrix[:]
copy2[0][0] = 100 # Всё равно изменяет matrix[0]!
# ПРАВИЛЬНО — глубокая копия
import copy
copy3 = copy.deepcopy(matrix)
copy3[0][0] = 100 # Теперь matrix не изменяется
Заключение и рекомендации
Двумерные массивы — важный инструмент программирования, который используется в играх, обработке данных, математике и многих других областях.
Основные выводы:
- В Python двумерные массивы реализуются как списки списков
- Доступ к элементам: matrix[i][j], где i — строка, j — столбец
- Для создания используй генераторы списков — они быстрее и безопаснее
- Для больших массивов и математики используй NumPy
- Вложенные циклы — основной способ обработки элементов
Что дальше изучать:
- Трёхмерные массивы (для работы с цветными изображениями, 3D-графикой)
- Алгоритмы на матрицах (поиск путей, динамическое программирование)
- Библиотека Pandas для работы с табличными данными
- Линейная алгебра с NumPy
Совет для практики: Решай задачи на двумерные массивы на платформах LeetCode, Codeforces, или Яндекс.Контест. Начни с простых задач (заполнение матрицы, поиск элементов), постепенно переходи к сложным (обход в спирали, динамическое программирование на матрицах).
Помни: понимание работы с двумерными массивами — это основа для изучения алгоритмов, машинного обучения и многих других областей программирования. Практикуйся регулярно, и скоро работа с матрицами станет для тебя интуитивно понятной!





