ТЕОРИЯ И ПРАКТИКА
-
Ввод и вывод данных
- Задачи
-
Условия
- Задачи
-
Цикл for
- Задачи
-
Строки
- Задачи
-
Цикл while
- Задачи
-
Списки
- Задачи
-
Двумерные массивы
- Задачи
-
Словари
- Задачи
-
Множества
- Задачи
-
Функции и рекурсия
- Задачи
Занятие 7. Двумерные массивы в питоне
Двумерные массивы Python: структура, данные, типичные представления
Что такое двумерные массивы в Python
Двумерный массив представляет собой структуру данных, организованную в виде таблицы, состоящей из строк и столбцов. Каждый элемент в этой таблице имеет два индекса: один для строки и один для столбца.
# Пример таблицы 2x3 (2 строки, 3 столбца)
table = [
[1, 2, 3],
[4, 5, 6]
]
Двумерные массивы находят применение в разработке игр для создания игровых полей, в обработке изображений для работы с пикселями, а также при работе с любыми табличными данными.
Двумерные массивы как списки списков
В Python двумерные массивы чаще всего реализуются как списки, элементами которых являются другие списки. Каждый вложенный список представляет собой одну строку массива.
# Каждая строка - отдельный список
shelf1 = [10, 20, 30]
shelf2 = [40, 50, 60]
box = [shelf1, shelf2]
print(box) # [[10, 20, 30], [40, 50, 60]]
Такая структура идеально подходит для хранения данных, где важна двумерная организация, например, для расписания уроков по дням недели и часам. Важно помнить о порядке индексов: сначала указывается индекс строки, а затем индекс столбца.
Ключевые отличия двумерных массивов от одномерных
Одномерный массив или список представляет собой простую линейную последовательность элементов. Двумерный же массив имеет более сложную, табличную структуру.
# Одномерный - просто список
line = [1, 2, 3, 4, 5]
# Двумерный - список списков
cinema = [
[1, 2, 3], # первый ряд
[4, 5, 6] # второй ряд
]
Одномерные списки удобны для простых последовательностей, таких как список покупок, в то время как двумерные массивы незаменимы для задач, требующих структурирования данных по двум осям, например, при планировании по времени и категориям.
Области применения двумерных массивов
Матрицы в математических вычислениях
В линейной алгебре и научных расчетах двумерные массивы используются для представления матриц, которые являются основой для множества сложных вычислений.
matrix = [
[1, 2],
[3, 4]
]
Представление изображений
Цифровое изображение по своей сути является двумерным массивом, где каждый элемент (пиксель) хранит информацию о цвете.
# Простое чёрно-белое изображение 3x3
image = [
[0, 1, 0], # 0 = чёрный, 1 = белый
[1, 1, 1],
[0, 1, 0]
]
Способы создания двумерных массивов в Python
Создание статического (заранее определенного) массива
Ручное объявление массива
Если все значения массива известны заранее, его можно объявить напрямую в коде.
menu = [
["каша", "суп", "котлета"], # понедельник
["омлет", "борщ", "рыба"], # вторник
["хлопья", "салат", "курица"] # среда
]
Пример: Игровое поле для крестиков-ноликов
Частый пример статического объявления — создание начального состояния игрового поля.
game_field = [
[" ", " ", " "],
[" ", " ", " "],
[" ", " ", " "]
]
Создание пустого или инициализированного массива
Использование генераторов списков
Для создания массивов заданного размера, заполненных начальными значениями (например, нулями или None), удобно использовать генераторы списков.
# Создаём пустую таблицу 3x4 (3 строки, 4 столбца), заполненную нулями
rows, cols = 3, 4
empty_table = [[0 for j in range(cols)] for i in range(rows)]
print(empty_table) # [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]
Важность глубокого копирования
При создании массивов следует избегать поверхностного копирования строк, так как это может привести к нежелательным последствиям, когда изменение элемента в одной строке затрагивает все остальные.
# НЕПРАВИЛЬНО: все строки ссылаются на один и тот же объект
bad_table = [[0] * 3] * 2
bad_table[0][0] = 5
print(bad_table) # [[5, 0, 0], [5, 0, 0]] - изменились обе строки!
# ПРАВИЛЬНО: каждая строка является независимым объектом
good_table = [[0 for _ in range(3)] for _ in range(2)]
good_table[0][0] = 5
print(good_table) # [[5, 0, 0], [0, 0, 0]] - изменилась только первая
Заполнение массива одним значением
Генераторы списков также позволяют легко заполнить весь массив одним и тем же значением.
# Заполнить всю таблицу 2x3 числом 7
value = 7
rows, cols = 2, 3
table = [[value for j in range(cols)] for i in range(rows)]
print(table) # [[7, 7, 7], [7, 7, 7]]
Создание массива из строки с разделителями
Разделение по пробелам и символам новой строки
Часто данные для двумерного массива поступают в виде одной строки, где строки разделены символом \n, а элементы — пробелами.
text = "1 2 3\n4 5 6\n7 8 9"
lines = text.split('\n') # разделяем на строки
table = []
for line in lines:
row = line.split(' ') # разделяем на элементы
table.append(row)
print(table) # [['1', '2', '3'], ['4', '5', '6'], ['7', '8', '9']]
Преобразование строковых элементов в числа
После разделения строки все элементы будут иметь строковый тип. Для математических операций их необходимо преобразовать в числа.
text = "1 2 3\n4 5 6"
lines = text.split('\n')
table = []
for line in lines:
row = [int(x) for x in line.split(' ')] # превращаем строки в числа
table.append(row)
print(table) # [[1, 2, 3], [4, 5, 6]]
Этот метод часто используется при чтении данных из файлов или обработке пользовательского ввода.
Работа с элементами двумерного массива
Чтение и изменение элементов по индексам
Чтение значения по индексам [row][col]
Доступ к конкретному элементу осуществляется путем указания его индексов строки и столбца. Помните, что индексация в Python начинается с 0.
cinema = [
["свободно", "занято", "свободно"],
["занято", "свободно", "занято"]
]
# Проверяем место во втором ряду, третье место
# Индекс строки 1 (второй ряд), индекс столбца 2 (третье место)
seat = cinema[1][2]
print(seat) # "занято"
Изменение значения по индексам
Аналогичным образом можно изменить значение любого элемента массива.
game = [
[".", ".", "."],
[".", ".", "."],
[".", ".", "."]
]
# Ставим крестик в центр поля (индексы 1, 1)
game[1][1] = "X"
print(game)
# Вывод:
# [['.', '.', '.'],
# ['.', 'X', '.'],
# ['.', '.', '.']]
Доступ к строкам и столбцам
Обращение к целой строке
Чтобы получить всю строку целиком, достаточно указать только ее индекс.
grades = [
[5, 4, 3], # математика
[4, 5, 5], # русский язык
[3, 4, 4] # физика
]
math_grades = grades[0] # все оценки по математике (первая строка)
print(math_grades) # [5, 4, 3]
Обращение к целому столбцу
Получение столбца требует итерации по всем строкам массива и извлечения элемента с нужным индексом столбца из каждой строки.
grades = [
[5, 4, 3], # оценки по 1, 2, 3 предмету
[4, 5, 5],
[3, 4, 4]
]
# Все оценки по второму предмету (индекс столбца 1)
second_subject_grades = [row[1] for row in grades]
print(second_subject_grades) # [4, 5, 4]
Безопасный доступ и обработка ошибок
Обработка исключения IndexError с помощью try-except
При попытке обратиться к несуществующему индексу возникнет ошибка IndexError. Ее можно перехватить с помощью блока try-except.
table = [[1, 2], [3, 4]]
try:
value = table[5][0] # такой строки не существует
print(value)
except IndexError:
print("Элемента с такими индексами в таблице нет!")
Предварительная проверка границ массива
Более надежный способ — проверять индексы перед обращением к элементу. Это позволяет избежать исключений и управлять логикой программы.
def safe_get(table, row, col):
# Проверяем, что индекс строки и столбца находятся в допустимых границах
if 0 <= row < len(table) and 0 <= col < len(table[0]):
return table[row][col]
else:
return None # или любое другое значение по умолчанию
table = [[1, 2], [3, 4]]
print(safe_get(table, 1, 1)) # 4
print(safe_get(table, 5, 0)) # None
Итерация и обход двумерных массивов
Простая итерация по строкам
Самый простой способ обхода — это перебор всех строк массива.
bookshelf = [
["Война и мир", "Анна Каренина"],
["Гарри Поттер", "Хоббит"],
["Шерлок Холмс", "Дракула"]
]
for shelf in bookshelf:
print("На полке находятся книги:", shelf)
Итерация по всем элементам через вложенные циклы
Для доступа к каждому отдельному элементу используются вложенные циклы: внешний цикл перебирает строки, а внутренний — элементы в текущей строке.
house = [
["диван", "стол", "стул"],
["кровать", "шкаф"],
["плита", "холодильник", "мойка"]
]
for room in house:
for item in room:
print("Найден предмет:", item)
Доступ к индексам с помощью range()
Если во время итерации необходимы индексы элементов, можно использовать функцию range() в сочетании с len().
storage = [
["молоток", "пила"],
["гвозди", "шурупы", "дюбели"],
["краска", "кисть"]
]
for i in range(len(storage)):
for j in range(len(storage[i])):
print(f"Полка {i}, ящик {j}: {storage[i][j]}")
Использование функции enumerate() для получения индексов и значений
Более "питонический" и удобный способ получить и индексы, и значения — это использовать функцию enumerate().
data = [
[10, 20],
[30, 40, 50],
[60]
]
for i, row in enumerate(data):
for j, value in enumerate(row):
print(f"Позиция ({i},{j}): {value}")
Основные операции с двумерными массивами
Транспонирование матрицы
Транспонирование — это операция, при которой строки и столбцы матрицы меняются местами.
Транспонирование через list comprehension
Это компактный и эффективный способ выполнить транспонирование.
original = [
[1, 2, 3],
[4, 5, 6]
]
transposed = [[row[i] for row in original] for i in range(len(original[0]))]
for i in transposed:
print(i)
Транспонирование с помощью функции zip()
Функция zip() в сочетании с оператором распаковки * предоставляет еще более элегантный способ.
original = [
[1, 2, 3],
[4, 5, 6]
]
# zip() возвращает итератор кортежей
transposed_tuples = list(zip(*original))
print(transposed_tuples) # [(1, 4), (2, 5), (3, 6)]
# Если на выходе нужны списки, а не кортежи
transposed_lists = [list(col) for col in zip(*original)]
print(transposed_lists) # [[1, 4], [2, 5], [3, 6]]
Поиск максимального значения
Поиск максимума в каждой строке
Можно легко найти максимальный элемент в каждой строке, применив функцию max() к каждому вложенному списку.
heights = [
[170, 180, 165],
[175, 190, 160],
[185, 155, 172]
]
for i, row in enumerate(heights):
max_height = max(row)
print(f"В ряду {i} максимальное значение: {max_height}")
Поиск абсолютного максимума во всем массиве
Чтобы найти максимальный элемент во всем двумерном массиве, можно использовать вложенный генератор.
heights = [
[170, 180, 165],
[175, 190, 160],
[185, 155, 172]
]
overall_max = max(max(row) for row in heights)
print(f"Максимальное значение во всем массиве: {overall_max}")
Вычисление суммы всех элементов
Сумму всех элементов можно найти, просуммировав суммы элементов каждой строки.
wallets = [
[100, 50, 200],
[75, 300, 25],
[150, 90]
]
total = sum(sum(row) for row in wallets)
print(f"Сумма всех элементов: {total}")
Проверка элементов на соответствие условиям
Эти операции широко применяются в анализе данных, статистике и контроле качества.
Проверка на наличие определенного типа значений
Функция any() позволяет проверить, выполняется ли условие хотя бы для одного элемента массива.
Пример: Поиск отрицательных чисел
temperatures = [
[5, -2, 10],
[15, 8, -5],
[20, 12, 18]
]
has_negative = any(temp < 0 for row in temperatures for temp in row)
print("В массиве есть отрицательные числа:", has_negative) # True
Подсчет количества элементов, удовлетворяющих условию
Функция sum() в сочетании с генераторным выражением позволяет подсчитать количество элементов, для которых условие истинно (так как True интерпретируется как 1, а False как 0).
Пример: Подсчет оценок
exam_results = [
[5, 4, 3, 5],
[4, 5, 5, 4],
[3, 4, 5, 3]
]
fives_count = sum(grade == 5 for row in exam_results for grade in row)
print(f"Количество оценок '5': {fives_count}")
Генерация двумерных массивов
Генерация матрицы на основе формулы
Генераторы списков позволяют создавать матрицы, значения элементов которых вычисляются по заданной формуле на основе их индексов.
# Таблица умножения 5x5
rows, cols = 5, 5
multiplication_table = [[(i + 1) * (j + 1) for j in range(cols)] for i in range(rows)]
# Выведем третью строку (умножение на 3)
print(multiplication_table[2]) # [3, 6, 9, 12, 15]
Генерация матрицы с использованием условий
В генераторы можно встраивать условные операторы для создания сложных структур.
# Шахматная доска 8x8 (0 и 1)
chessboard = [[1 if (i + j) % 2 == 0 else 0 for j in range(8)] for i in range(8)]
Часто используемые типы матриц
Нулевая матрица
Матрица, все элементы которой равны нулю.
# Матрица из нулей размером 4x4
zeros = [[0 for j in range(4)] for i in range(4)]
print(zeros)
Единичная матрица
Квадратная матрица, у которой на главной диагонали стоят единицы, а все остальные элементы равны нулю.
# Единичная матрица 3x3
identity = [[1 if i == j else 0 for j in range(3)] for i in range(3)]
print(identity) # [[1, 0, 0], [0, 1, 0], [0, 0, 1]]
Диагональная матрица
Квадратная матрица, у которой все элементы вне главной диагонали равны нулю.
# Матрица с заданными числами по диагонали
diagonal_values = [2, 4, 6]
size = len(diagonal_values)
diagonal_matrix = [[diagonal_values[i] if i == j else 0 for j in range(size)] for i in range(size)]
print(diagonal_matrix) # [[2, 0, 0], [0, 4, 0], [0, 0, 6]]
Дополнительные возможности: преобразование в другие структуры данных
Преобразование в список кортежей
Иногда требуется преобразовать строки массива в неизменяемые кортежи.
table = [
[1, 2, 3],
[4, 5, 6]
]
tuple_list = [tuple(row) for row in table]
print(tuple_list) # [(1, 2, 3), (4, 5, 6)]
Получение множества уникальных элементов
Чтобы получить все уникальные значения из двумерного массива, его можно "развернуть" в одномерную последовательность и преобразовать в множество.
table = [
[1, 2, 3],
[2, 3, 4],
[3, 4, 5]
]
unique_elements = set(element for row in table for element in row)
print(unique_elements) # {1, 2, 3, 4, 5}
Эта операция полезна для анализа уникальности данных и подготовки их к дальнейшей обработке. Следует помнить, что при преобразовании в множество исходный порядок элементов теряется.