Matrices#
(Click here for the German version of this page)
Matrices are multi-dimensional vectors. Or the in the context of Python, multi-dimensional lists.
When working with multi-dimensional data, regular multi-dimensional lists are often not sufficient. In those cases, well-known external libraries, such as numpy or pandas, are often used.
Just like mentioned at the start of this introduction, the goal is not to write good software in Python, but instead to understand the underlying concepts. Therefore, instead of working external libraries, only regular multi-dimensional lists will be used.
What are multi-dimensional lists in Python#
Multi-dimensional lists in Python are relatively easy. Since lists can be nested in each other, a two-dimensional list would just be a list of lists. A three-dimensional list would be a list of lists of lists and so on. For this introduction only two-dimensional lists are used since they are by the far the most common form of the multi-dimensional lists in regard to algorithms. The concepts are similar for higher dimensions.
Creation of a multi-dimensional list#
Two create an empty two-dimensional list, one can define an empty list and then insert lists into it one after another.
matrix = []
matrix.append( [1, 2, 3] )
matrix.append( [4, 5, 6] )
print(matrix)
# --> [[1, 2, 3],
# [4, 5, 6]]
Creation of a two-dimensional list can be done more elegantly with list comprehension, but this will not be discussed in this introduction. For those interested, they may research the term themselves.
Access#
To access a two-dimensional list, two indexing operations, one after another, are performed.
a = [
[1,2,3],
[4,5,6],
[7,8,9]
]
print( a[0][0] )
# --> 1
The first index is the index of the row, and the second index is the index of the columns. One can visualize it like this: The first index decides which of the three lists is selected. The second index then selects the actual element of one of those lists.
a = [
[1,2,3],
[4,5,6],
[7,8,9]
]
# Entire matrix
print( a )
# --> [[1, 2, 3],
# [4, 5, 6],
# [7, 8, 9]]
# Row index 1
print( a[1] )
# --> [4, 5, 6]
# Row index 1 column index 2
print( a[1][2] )
# --> 6
# What about column index 2?
# Not as easy.
# Either manual iteration
# or nested list comprehension
# required (not explained further)
print([row[2] for row in a])
# --> [3, 6, 9]
Inserting rows#
A multi-dimensional list in Python is treated just like a regular list and does not have a special data type and no special methods.
Therefore, insertion of rows and columns must be implemented by yourself. Most algorithms know beforehand how many columns and rows are necessary. One example would be the Floyd–Warshall algorithm. In a nutshell, the algorithm calculates the shortest path from every node to all others. The distance between nodes can be represented as a two-dimensional list. Here is an example with three nodes A, B and C.
A |
B |
C |
|
|---|---|---|---|
A |
0 |
15 |
53 |
B |
7 |
0 |
3 |
C |
32 |
42 |
0 |
The table is interpreted, that e.g., row A and column B means that the path from A to B is 15 units long. Since one calculates the paths from all nodes to all others, one knows that a matrix of dimensions 3 x 3 is required.
Since no additional rows or columns must be inserted, it is not too big of a deal, that there are no special methods for that.
If one wants to insert rows and columns, then one would have to think of something.
Exercise#
If you want, you can think about how to implement methods for inserting rows and columns respectively.
For simplicity, you can assume that the input is always correct. For example, when inserting a new row into a matrix with 3 columns, then the new row will also have 3 columns. Likewise, when inserting a new column into a matrix with 4 rows, then the new column will also have 4 rows.
# Here you can attempt to solve this problem...
def insert_row(matrix, row_index, row_values):
...
def insert_column(matrix, column_index, column_values):
...
a = [
[1,2,3],
[4,5,6],
[7,8,9]
]
print(a)
# Should output: [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
# Cleaner representation:
# [[1, 2, 3],
# [4, 5, 6],
# [7, 8, 9]]
# After this operation, the values [-2, -1, 0] should be in the third row (row index 2)
insert_row(a, 2, [-2, -1, 0])
print(a)
# Should output: [[1, 2, 3], [4, 5, 6], [-2, -1, 0], [7, 8, 9]]
# Cleaner representation:
# [[ 1, 2, 3],
# [ 4, 5, 6],
# [-2, -1, 0],
# [ 7, 8, 9]]
# After this operation, the values [10, 11, 12, 13] should be in the second column (column index 1)
insert_column(a, 1, [10, 11, 12, 13])
print(a)
# Should output: [[1, 10, 2, 3], [4, 11, 5, 6], [-2, 12, -1, 0], [7, 13, 8, 9]]
# Cleaner representation:
# [[ 1, 10, 2, 3],
# [ 4, 11, 5, 6],
# [-2, 12, -1, 0],
# [ 7, 13, 8, 9]]
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
Solution
# Here you can attempt to solve this problem...
def insert_row(matrix, row_index, row_values):
matrix.insert(row_index, row_values)
def insert_column(matrix, column_index, column_values):
for row_index in range(0, len(matrix)):
matrix[row_index].insert(column_index, column_values[row_index])
a = [
[1,2,3],
[4,5,6],
[7,8,9]
]
print(a)
# Should output: [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
# Cleaner representation:
# [[1, 2, 3],
# [4, 5, 6],
# [7, 8, 9]]
# After this operation, the values [-2, -1, 0] should be in the third row (row index 2)
insert_row(a, 2, [-2, -1, 0])
print(a)
# Should output: [[1, 2, 3], [4, 5, 6], [-2, -1, 0], [7, 8, 9]]
# Cleaner representation:
# [[ 1, 2, 3],
# [ 4, 5, 6],
# [-2, -1, 0],
# [ 7, 8, 9]]
# After this operation, the values [10, 11, 12, 13] should be in the second column (column index 1)
insert_column(a, 1, [10, 11, 12, 13])
print(a)
# Should output: [[1, 10, 2, 3], [4, 11, 5, 6], [-2, 12, -1, 0], [7, 13, 8, 9]]
# Cleaner representation:
# [[ 1, 10, 2, 3],
# [ 4, 11, 5, 6],
# [-2, 12, -1, 0],
# [ 7, 13, 8, 9]]