Двумерные массивы в 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.
Обычно для обработки и вывода списка применяется два вложенных цикла: по номеру строки и по элементам внутри строки.
Пример вывода двумерного числового списка на экран по строкам (числа разделены внутри одной строки с помощью пробелов):
for i inrange(len(A)):
for j inrange(len(A[i]):
print(A[i][j], end=’ ‘)
print()
Такой же пример, но циклы по значением списка, а не по индексу:
forrowin A:
foreleminrow:
print(elem, end=’ ‘)
print()
Пример вывода одной строки с помощью метода join:
forrowin A:
print(‘ ‘.join(list(map(str, row))))
Чтобы суммировать все числа в списке, применяем два вложенных цикла:
S = 0
for i inrange(len(A)):
for j inrange(len(A[i])):
S += A[i][j]
Такой же пример, только по значением строк:
S = 0
forrowin A:
foreleminrow:
S += elem
Создание вложенных списков
Например, даны два числа: n – количество строк и m – количество столбцов. Нужно создать список размером n×m, заполнив его нулями:
Очевидное решение получилось неверным:
# Неправильно
A = [[0] * m] * n
Чтобы убедиться в этом, достаточно присвоить значение 1 элементу A[0][0], после чего вывести значение другого элемента A[1][0], которое тоже будет 1. Все потому, что 0] * m возвращает ссылку на список из m нулей. Однако дальнейшее повторение данного элемента создает список из элементов n, которые выступают ссылкой, ведущей на один и тот же список, поэтому все строки списка являются одной и той же строкой.
Двумерный список нельзя создавать посредством операции повторений одной строки. Как найти выход? Существует несколько решений.
Первое решение: создайте список из n элементов (например, из n нулей). После чего сделайте каждый элемент списка в виде ссылки на другой одномерный список, состоявший из m элементов:
A = [0] * n
for i inrange(n):
A[i] = [0] * m
Второе решение (похожее): для начала создайте пустой список, затем n раз добавьте в него новый элемент, выступающий списком-строкой:
A = []
for i inrange(n):
A.append([0] * m)
Однако проще всего воспользоваться генератором, а именно создать список из n элементов, каждый из которых тоже будет списком из m нулей:
A = [[0] * m for i inrange(n)]
В таком случае каждый элемент будет создаваться независимо от других (для заполнения очередного элемента списка заново конструируется список [0] * m, а не копируются ссылки на один и тот же список.
Ввод двумерного массива
Программа получает двумерный массив на вход представленный n строками, каждая из которых содержит m чисел, которые разделены пробелами. Сосчитать их можно следующим образом:
A = []
for i inrange(n):
A.append(list(map(int, input().split())))
Есть еще один способ – не прибегать к сложных вложенных вызов функций:
A = []
for i inrange(n):
row = input().split()
for i inrange(len(row)):
row[i] = int(row[i])
A.append(row)
Также можно воспользоваться генератором:
A = [list(map(int, input().split())) for i inrange(n)]
Обработка двумерного массива
Перед вам квадратный массив, состоящий из n строк и n столбцов. Элементам на главной диагонали, проходящий от левого верхнего в правый нижний угол(тем элементамA[i][j], для которых ij) необходимо присвоить значение 1, а элементам выше главной диагонали – значение 0, элементам, что ниже главной диагонали – 2. Получиться такой массив (для n=4):
1 0 0 0
2 1 0 0
2 2 1 0
2 2 2 1
Решить такую задачу можно несколькими способами. Элементы, лежащие выше главной диагонали -[i][j], для которых i<диагонали – это элементы A[i][j], для которых i<j, а для элементов ниже главной диагонали i>j. Так, можно сравнить значение i и j и определить значение A[i][j]. Получиться следующий алгоритм:
for i inrange(n):
for j inrange(n):
if i < j:
A[i][j] = 0
elifi > j:
A[i][j] = 2
else:
A[i][j] = 1
Этот алгоритм плохой, так как выполняет 1-2 функции if, чтобы обработать каждый элемент. Если несколько усложнить алгоритм, то можно и вовсе обойтись без условных инструкций. В первую очередь заполните главную диагональ. Здесь потребуется один цикл:
for i inrange(n):
A[i][i] = 1
Далее заполните все элементы главной диагонали значением 0. Для этого в каждой из строй с номером i присвоить значение элементам A[i][j] для j=i+1, …, n-1. Потребуются вложенные циклы:
for i inrange(n):
for j inrange(i + 1, n):
A[i][j] = 0
Точно также присваиваем элементам A[i][j] для j=0, …, i-1 значение 2:
for i inrange(n):
for j inrange(0, i):
A[i][j] = 2
Также можно объединить внешние циклы в один, чтобы получить более компактное решение:
for i inrange(n):
for j inrange(0, i):
A[i][j] = 2
A[i][i] = 1
for j inrange(i + 1, n):
A[i][j] = 0
Еще одно решение, которое подразумевает использование операции повторения списков с целью построения очередной строки списка . i-я строка списка состоит из i чисел 2, а после него одно число 1, затем идет n-i-1 число 0:
for i inrange(n):
A[i] = [2] * i + [1] + [0] * (n — i — 1)
Цикл можно заменить на генератор:
A = [[2] * i + [1] + [0] * (n — i — 1) for i inrange(n)]
Вложенные генераторы двумерных массивов
Вложенные генераторы успешно используются для создания двумерных массивов. Разместите генератор списка, выступающий строкой, внутри генератора для строк. К примеру, сделайте список из n строк и m столбцов посредством генератора, создающего список из n элементов. При этом каждый элемент будет списком из m нулей:
[[0] * m for i inrange(n)]
Внутренний список так можно создать с помощью следующего генератора: [0 for j inrange(m)]. После того как вы вложите один генератор в другой получится вложенные генераторы:
[[0 for j inrange(m)] for i inrange(n)]
Однако если заменить число 0 на некоторое выражение, зависящее от j (номер столбца) и i (номер строки), то получите список, заполненный по некоторой формуле.
Представьте, что нужно задать следующий массив (дополнительные пробелы между элементами были добавлены для удобства):
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
В текущем массиве m = 6 столбцов, n = 5 строк, и элемент в столбце j и строке i вычисляется по формуле:
A[i][j] = i * j.
Чтобы создать такой массив можно применять генератор:
[[i * j for j inrange(m)] for i inrange(n)]