Матрицы. Основы

Что такое матрица? Создание, вывод на экран

Введение 

Очень часто при работе с какой-либо информацией приходится иметь дело с табличными данными. Современные программы очень часто работают именно с такими данными. Самый простой пример - это программирование игр на клетчатой доске: крестики-нолики, шахматы, шашки и т.п.

В математике такие структуры называются матрицами
 
Матрица - это прямоугольная таблица составленная из элементов одного типа (чиcел, строк и т.д)

Такие данные на языке Питон можно хранить и обрабатывать в виде двумерных списков (двумерных массивов) - "список списков".
Чтобы обработать данные в таблице, надо запоминать состояние каждой ячейки (клетки). Каждая ячейка имеет два номера: номер строки и номер столбца.
В матрице каждый элемент имеет два индекса: сначала указывается номер строки, затем номер столбца. Нумерация строк и столбцов начинается с нуля.
Например, элемент A[1][2] - это элемент расположенный во второй строке и третьем столбце.

Так же как и с обычными массивами (списками), для того, чтобы работать с матрицами, необходимо научиться их создавать, вводить, обрабатывать и выводить на экран.

Создание матрицы

Вариант 1: Строгое задание элементов матрицы
Если известны все значения матрицы, то ее можно записать следующим образом (для таблицы, указанной выше):
 
arr = [ [1, 2, 4, 29],
        [3, 4, 6, 1] ]
или в одну строку
arr = [[1, 2, 4, 29], [3, 4, 6, 1]]
Первый способ более нагляден, лучше читается и воспринимается
Обратите внимание, значения элементов каждой строки располагаются в квадратных скобках.

Вариант 2. Создание в памяти матрицы заданного размера, заполненной некоторыми начальными значениями (например, нулями)

НЕВЕРНЫЙ способ (так делать точно не надо)

N = 3
M = 2
row = [0] * M  # создаем список-строку длиной M
A = [row] * N  # создаем массив (список) из N строк


Такой способ будет работать неверно из-за особенностей Питона. 
Если потом необходимо будет сделать присваивание A[0][0] = 1, то в результате все элементы нулевого столбца будет равны 1
Вывод матрицы А на экран командой print(A) даст результат (проверьте это самостоятельно):
[[1, 0], [1, 0], [1, 0]]
Это произошло из-за того, что матрица - это список адресов строк. 
То есть выполняя оператор
row = [0] * M 
компилятор создаст в памяти одну-единственную строку, а затем оператор
A = [row] * N 
устанавливает на эту строку все ссылки в массиве А.
ДЕЛАЕМ ПРАВИЛЬНО!
Чтобы создать правильно матрицу, необходимо заставить компилятор создать все строки в памяти как разные объекты.
Для этого необходимо сначала создать пустой список, а затем в цикле добавлять к нему новые строки с помощью метода append()
N = 3
M = 2
A = []
for i in range(N):
    A.append([0]*M)
сделать то же самое можно с помощью генератора
N = 3
M = 2
A = [ [0]*M for i in range(N) ]

 

Заполнение матрицы произвольными значениями

После создания матрицы можно заполнить ее произвольными значениями. Так как каждый элемент имеет два индекса, то необходимо использовать вложенные циклы
for i in range(N):
    for j in range(M):
        A[i][j] = ...
 

Вывод матрицы на экран

Вариант 1. Простейший способ
Вывод матрицы в одну строку

print(A)
Минус: не удобно в восприятии

Вариант 2.

Для обработки и вывода списка, как правило, используется два вложенных цикла. Первый цикл по номеру строки, второй цикл - по элементам внутри строки.
Для того, чтобы вывести матрицу на экран построчно, разделяя числа пробелами внутри одной строки, необходимо написать такой фрагмент:

for i in range(len(A)):                 # len(A) - возвращает количество строк в матрице А
    for j in range(len(A[i])):           # len(A[i]) - возвращает количество элементов в строке i
        print(A[i][j], end = ' ')
    print()                             # делаем переход на новую строку после вывода на экран строки

То же самое, но циклы не по индексу, а по значениям списка (цикл for умеет делать перебор всех элементов в списке (массиве), строке):

for row in A:                          # делаем перебор всех строк матрицы A
    for elem in row:                   # перебираем все элементы в строке row
        print(elem, end = ' ')
    print()

Для вывода одной строки можно воспользоваться методом join:

for row in A:
    print(' '.join(list(map(str, row))))

Заполнение матрицы с клавиатуры

Заполнение матрицы значениями с клавиатуры

Пусть программа получает на вход двумерный массив, в виде n строк, каждая из которых содержит m чисел, разделенных пробелами. Как их считать? Например, так:

A = []
for i in range(n):
    A.append(list(map(int, input().split())))   #метод list() создает список(массив) из набора данных, указанных в скобках

Или, без использования сложных вложенных вызовов функций:

A = []
for i in range(n):
    row = input().split()      # считали строку с числами, разбили на элементы по пробелам (получили массив row)
    for i in range(len(row)):
        row[i] = int(row[i])   # каждый элемента списка row преобразовали в число
    A.append(row)              # добавили массив row к массиву A

 

Перебор элементов матрицы

Каждый элемент матрицы имеет два индекса, поэтому для перебора всех элементов нужно использовать вложенный цикл.
Обычно матрицу перебирают по строкам: внешний цикл перебирает индексы строк, а внутренний - индексы столбцов.
Но при необходимости можно перебирать матрицу и по столбцам, тогда циклы меняются местами.