Matrices: list of lists
Download exercises zip
Introduction
There are a couple of ways in Python to represent matrices: as lists of lists, or with the external library Numpy. The most used is surely Numpy but we see both representations anyway. Let’s see the reason and main differences:
Lists of lists - as in this notebook:
native in Python
not efficient
lists are pervasive in Python, you will probably encounter matrices expressed as lists of lists anyway
you get an idea of how to construct a nested data structure
we can discuss memory referencies and copies along the way
Numpy - see other tutorial Numpy matrices
not natively available in Python
efficient
used by many scientific libraries (scipy, pandas)
the syntax to access elements is slightly different from lists of lists
in rare cases it might bring installation problems and/or conflicts (implementation is not pure Python)
What to do
unzip exercises in a folder, you should get something like this:
matrices-lists
matrices-lists1.ipynb
matrices-lists1-sol.ipynb
matrices-lists2.ipynb
matrices-lists2-sol.ipynb
matrices-lists3-chal.ipynb
jupman.py
WARNING: to correctly visualize the notebook, it MUST be in an unzipped folder !
open Jupyter Notebook from that folder. Two things should open, first a console and then browser. The browser should show a file list: navigate the list and open the notebook
matrices-lists/matrices-lists1.ipynb
Go on reading that notebook, and follow instuctions inside.
Shortcut keys:
to execute Python code inside a Jupyter cell, press
Control + Enter
to execute Python code inside a Jupyter cell AND select next cell, press
Shift + Enter
to execute Python code inside a Jupyter cell AND a create a new cell aftwerwards, press
Alt + Enter
If the notebooks look stuck, try to select
Kernel -> Restart
Overview
Let’s see these lists of lists. Consider the following a matrix with 3 rows and 2 columns, or in short 3x2 matrix:
[2]:
m = [
['a','b'],
['c','d'],
['a','e']
]
For convenience, we assume as input to our functions there won’t be matrices with no rows, nor rows with no columns.
Going back to the example, in practice we have a big external list:
m = [
]
and each of its elements is another list which represents a row:
m = [
['a','b'],
['c','d'],
['a','e']
]
So, to access the whole first row ['a','b']
, we would simply access the element at index 0 of the external list m
:
[3]:
m[0]
[3]:
['a', 'b']
To access the second whole second row ['c','d']
, we would access the element at index 1 of the external list m
:
[4]:
m[1]
[4]:
['c', 'd']
To access the second whole third row ['c','d']
, we would access the element at index 2 of the external list m
:
[5]:
m[2]
[5]:
['a', 'e']
To access the first element 'a'
of the first row ['a','b']
we would add another subscript operator with index 0:
[6]:
m[0][0]
[6]:
'a'
To access the second elemnt 'b'
of the first row ['a','b']
we would use instead index 1 :
[7]:
m[0][1]
[7]:
'b'
WARNING: When a matrix is a list of lists, you can only access values with notation m[i][j]
, NOT with m[i,j]
!!
[8]:
# write here the wrong notation m[0,0] and see which error you get:
Matrix dimensions
✪ EXERCISE: For getting matrix dimensions, we can use normal list operations. Which ones? You can assume the matrix is well formed (all rows have equal length) and has at least one row and at least one column
[9]:
m = [
['a','b'],
['c','d'],
['a','e']
]
[10]:
# write here code for printing row and column dimensions
Visiting with style
Suppose we want to visit all the cells of a matrix from left to right, and print them one by one.
If you want to keep track of the coordinates where you are in the traversal, you can use a nested for in range
like so:
[11]:
m = [
['a','b','c'],
['d','e','f'],
['g','h','i'],
['m','n','o'],
]
for i in range(len(m)):
for j in range(len(m[0])):
print('i:', i, ' j:', j, ' m[i][j]:', m[i][j])
print("ROW END!")
i: 0 j: 0 m[i][j]: a
i: 0 j: 1 m[i][j]: b
i: 0 j: 2 m[i][j]: c
ROW END!
i: 1 j: 0 m[i][j]: d
i: 1 j: 1 m[i][j]: e
i: 1 j: 2 m[i][j]: f
ROW END!
i: 2 j: 0 m[i][j]: g
i: 2 j: 1 m[i][j]: h
i: 2 j: 2 m[i][j]: i
ROW END!
i: 3 j: 0 m[i][j]: m
i: 3 j: 1 m[i][j]: n
i: 3 j: 2 m[i][j]: o
ROW END!
The algorithm is pretty simple, yet a couple of things are worth noting:
we used
i
as integer index for the rowswe used
j
as integer index for the columns
Those names and types are important, as they are basically standard in math books.
You could maybe dismiss name choices as a pure matter of style, yet:
WHEN DEALING WITH MATRICES, STYLE *IS* SUBSTANCE
Please adopt the above naming style.
Those who don’t, spend quite a lot of time in Debugging Hell… trust us.
Question - A matter of style 1
Look at the following code that prints again all the cells from left to right (suppose we don’t care about printing the coordinates).
Is this good style or not? Why?
[12]:
m = [
['a','b','c'],
['d','e','f'],
['g','h','i'],
['m','n','o'],
]
for i in m:
for j in i:
print(j)
print("ROW END!")
a
b
c
ROW END!
d
e
f
ROW END!
g
h
i
ROW END!
m
n
o
ROW END!
Question - A matter of style 2
Look at the following code that prints again alle the cells from left to right (suppose we don’t care about printing the coordinates).
Is this good style or not? Why?
[13]:
m = [
['a','b','c'],
['d','e','f'],
['g','h','i'],
['m','n','o'],
]
for row in range(len(m)):
for column in range(len(m[0])):
print(m[row][column])
print("ROW END!")
a
b
c
ROW END!
d
e
f
ROW END!
g
h
i
ROW END!
m
n
o
ROW END!
Question - A matter of style 3
Look at the following code that prints again alle the cells from left to right (suppose we don’t care about printing the coordinates).
Is this good style or not? Why?
[14]:
m = [
['a','b','c'],
['d','e','f'],
['g','h','i'],
['m','n','o'],
]
for row in m:
for cell in row:
print(cell)
print("ROW END!")
a
b
c
ROW END!
d
e
f
ROW END!
g
h
i
ROW END!
m
n
o
ROW END!
How to solve the exercises
All the following exercises are proposed as functions to implement.
REMEMBER: if the cell is executed and nothing happens, it’s because all the assert tests have worked! In such case you probably wrote correct code but careful, these kind of tests are never exhaustive so you could have still made some error.
III COMMANDMENT: You shall never reassign function parameters
VI COMMANDMENT You shall use return
command only if you see written RETURN in the function description!
Extracting rows and columns
How to extract a row
One of the first things you might want to do is to extract the i
-th row. If you’re implementing a function that does this, you have basically two choices. Either:
return a pointer to the original row
return a copy of the row.
Since a copy consumes memory, why should you ever want to return a copy? Sometimes you just don’t know which use will be done of the data structure. For example, suppose you got a book of exercises which has empty spaces to write exercises in. It’s such a great book everybody in the classroom wants to read it - but you are afraid if the book starts changing hands some careless guy might write on it. To avoid problems, you make a copy of the book and distribute it (let’s leave copyright infringment matters aside :-)
Extracting row pointers
So first let’s see what happens when you just return a pointer to the original row.
NOTE: For convenience, at the end of the cell we put a magic call to jupman.pytut()
which shows the code execution like in Python tutor (for further info about jupman.pytut()
, see here). If you execute all the code in Python tutor, you will see that at the end you have two arrow pointers to the row ['a','b']
, one starting from m
list and one from row
variable.
[15]:
# WARNING: FOR PYTHON TUTOR TO WORK, REMEMBER TO EXECUTE THIS CELL with Shift+Enter
# (it's sufficient to execute it only once)
import jupman
[16]:
def extrowp(mat, i):
""" RETURN the ith row from mat
"""
return mat[i]
m = [
['a','b'],
['c','d'],
['a','e'],
]
row = extrowp(m, 0)
jupman.pytut()
[16]:
Extract row with a for
✪ Now try to implement a version which returns a copy of the row.
QUESTION: You might be tempted to implement something like this - but it wouldn’t work. Why?
[17]:
# WARNING: WRONG CODE!!!!
def extrow_wrong(mat, i):
""" RETURN the ith row from mat, as a NEW list"""
row = []
row.append(mat[i])
return row
m = [
['a','b'],
['c','d'],
['a','e'],
]
row = extrow_wrong(m,0)
jupman.pytut()
[17]:
You can build an actual copy in several ways, with a for
, a slice or a list comprehension. Try to implement all versions, starting with the for
here. Be sure to check your result with Python Tutor - to visualize python tutor inside the cell output, you might use the special command jupman.pytut()
at the end of the cell as we did before. If you run the code with Python Tutor, you should only see one arrow going to the original ['a','b']
row in m
, and there should be
another ['a','b']
copy somewhere, with row
variable pointing to it.
✪ EXERCISE: Implement the function esrowf
which RETURNS the i
-th row from mat
as a NEW list.
NOTE: To create a new list use a for cycle which iterates over the elements, not the indeces (so don’t use range!)
[18]:
def extrowf(mat, i):
raise Exception('TODO IMPLEMENT ME !')
m = [
['a','b'],
['c','d'],
['a','e'],
]
assert extrowf(m, 0) == ['a','b']
assert extrowf(m, 1) == ['c','d']
assert extrowf(m, 2) == ['a','e']
# check it didn't change the original matrix !
r = extrowf(m, 0)
r[0] = 'z'
assert m[0][0] == 'a'
# uncomment to visualize execution here
#jupman.pytut()
Extract row with range
Let’s first rapidly see range(n)
. Maybe you think it should return a sequence of integers, from zero to n - 1
. Is it really like this?
[19]:
range(5)
[19]:
range(0, 5)
Maybe you expected something like a list [0,1,2,3,4]
, instead we discovered that Python is quite lazy here: as a matter of fact, range(n)
returns an iterable object, which is not a real sequence materialized in memory.
To take a real integer list, we must explicitly ask this iterable object to give us the objects one by one.
When you write for i in range(s)
the for
loop is doing exactly this, at each round it asks the object range
to generate a number from the sequence. If we want the whole sequence materialized in memory, we can generate it by converting the range
into a list object:
[20]:
list(range(5))
[20]:
[0, 1, 2, 3, 4]
Be careful, though. According to the sequence dimension, this might be dangerous. A billion elements list might saturate your computer RAM (in 2020 notebooks often have 4 gigabytes of RAM, that is, 4 billion bytes).
✪ EXERCISE: Now implement the extrowr
iterating over a range of row indexes:
NOTE 1: To create a new list use a
for
loopNOTE 2: remember to use a new name for the column index!
[21]:
def extrowr(mat, i):
""" RETURN the ith row from mat as a NEW list
"""
raise Exception('TODO IMPLEMENT ME !')
m = [
['a','b'],
['c','d'],
['a','e'],
]
assert extrowr(m, 0) == ['a','b']
assert extrowr(m, 1) == ['c','d']
assert extrowr(m, 2) == ['a','e']
# check it didn't change the original matrix !
r = extrowr(m, 0)
r[0] = 'z'
assert m[0][0] == 'a'
# uncomment to visualize execution here
#jupman.pytut()
Extract row with a slice
✪ Remember slices return a copy of a list? Now try using them.
Implement extrows
, which RETURN the i
-th row from mat
as a NEW list.
NOTE: To create it, use slices
[22]:
def extrows(mat, i):
raise Exception('TODO IMPLEMENT ME !')
m = [
['a','b'],
['c','d'],
['a','e'],
]
assert extrows(m, 0) == ['a','b']
assert extrows(m, 1) == ['c','d']
assert extrows(m, 2) == ['a','e']
# check it didn't change the original matrix !
r = extrows(m, 0)
r[0] = 'z'
assert m[0][0] == 'a'
# uncomment to visualize execution here
#jupman.pytut()
Extract row with list comprehension
✪ Implement extrowc
, which RETURNs the i
-th row from mat
as a NEW list, using a list comprehension.
[23]:
def extrowc(mat, i):
raise Exception('TODO IMPLEMENT ME !')
m = [
['a','b'],
['c','d'],
['a','e'],
]
assert extrowc(m, 0) == ['a','b']
assert extrowc(m, 1) == ['c','d']
assert extrowc(m, 2) == ['a','e']
# check it didn't change the original matrix !
r = extrowc(m, 0)
r[0] = 'z'
assert m[0][0] == 'a'
#jupman.pytut()
Extract column with a for
✪✪ Now try extracting a column at j
th position. This time we will be forced to create a new list, so we don’t have to wonder if we need to return a pointer or a copy.
Implement extcolf
, which RETURN the j
-th column from mat
. To create it, use a for
loop.
[24]:
def extcolf(mat, j):
raise Exception('TODO IMPLEMENT ME !')
m = [
['a','b'],
['c','d'],
['a','e'],
]
assert extcolf(m, 0) == ['a','c','a']
assert extcolf(m, 1) == ['b','d','e']
# check returned column does not modify m
c = extcolf(m,0)
c[0] = 'z'
assert m[0][0] == 'a'
#jupman.pytut()
Extract column with a list comprehension
✪✪ Implement extcolc
, which RETURNS the j
-th column from mat
: to create it, use a list comprehension.
[25]:
def extcolc(mat, j):
raise Exception('TODO IMPLEMENT ME !')
m = [
['a','b'],
['c','d'],
['a','e'],
]
assert extcolc(m, 0) == ['a','c','a']
assert extcolc(m, 1) == ['b','d','e']
# check returned column does not modify m
c = extcolc(m,0)
c[0] = 'z'
assert m[0][0] == 'a'
#jupman.pytut()
Creating new matrices
empty matrix
✪✪ There are several ways to create a new empty 3x5 matrix as lists of lists which contains zeros.
Implement empty_matrix
, which RETURN a NEW matrix nxn as a list of lists filled with zeroes
use two nested
for
cycles:
[26]:
def empty_matrix(n, m):
raise Exception('TODO IMPLEMENT ME !')
assert empty_matrix(1,1) == [[0]]
assert empty_matrix(1,2) == [ [0,0] ]
assert empty_matrix(2,1) == [ [0],
[0] ]
assert empty_matrix(2,2) == [ [0,0],
[0,0] ]
assert empty_matrix(3,3) == [ [0,0,0],
[0,0,0],
[0,0,0] ]
empty_matrix
the elegant way
To create a new list of 3 elements filled with zeros, you can write like this:
[27]:
[0]*3
[27]:
[0, 0, 0]
The *
is kind of multiplying the elements in a list
Given the above, to create a 5x3 matrix filled with zeros, which is a list of seemingly equal lists, you might then be tempted to write like this:
[28]:
# WRONG
[[0]*3]*5
[28]:
[[0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]]
Why is that (possibly) wrong? Let’s try to inspect it in Python Tutor:
[29]:
bad = [[0]*3]*5
jupman.pytut()
[29]:
If you look closely, you will see many arrows pointing to the same list of 3 zeros. This means that if we change one number, we will apparently change 5 of them in the whole column !
The right way to create a matrix as list of lists with zeroes is the following:
[30]:
# CORRECT
[[0]*3 for i in range(5)]
[30]:
[[0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]]
EXERCISE: Try creating a matrix with 7 rows and 4 columns and fill it with 5.
Show solution[31]:
# write here
[31]:
[[5, 5, 5, 5],
[5, 5, 5, 5],
[5, 5, 5, 5],
[5, 5, 5, 5],
[5, 5, 5, 5],
[5, 5, 5, 5],
[5, 5, 5, 5]]
deep_clone
✪✪ Let’s try to produce a complete clone of the matrix, also called a deep clone, by creating a copy of the external list and also the internal lists representing the rows.
QUESTION: You might be tempted to write code like this, but it will not work. Why?
[32]:
# WARNING: WRONG CODE
def deep_clone_wrong(mat):
""" RETURN a NEW list of lists which is a COMPLETE DEEP clone
of mat (which is a list of lists)
"""
return mat[:]
m = [
['a','b'],
['b','d']
]
res = deep_clone_wrong(m)
# Notice you will have arrows in res list going to the _original_ mat. We don't want this !
jupman.pytut()
[32]:
To fix the above code, you will need to iterate through the rows and for each row create a copy of that row.
✪✪ EXERCISE: Implement deep_clone
, which RETURNS a NEW list as a complete DEEP CLONE of mat
(which is a list of lists)
NOTE: the exercise can be solved very quickly by using the function deepcopy but we invite you to solve it without for now.
Show solution[33]:
def deep_clone(mat):
raise Exception('TODO IMPLEMENT ME !')
m = [ ['a','b'],
['b','d'] ]
res = [ ['a','b'],
['b','d'] ]
# verify the copy
c = deep_clone(m)
assert c == res
# verify it is a DEEP copy (that is, it created also clones of the rows!)
c[0][0] = 'z'
assert m[0][0] == 'a'
Modifying matrices
fillc
✪✪ Implement the function fillc
which takes as input mat
(a list of lists with dimension nrows
x ncol
) and MODIFIES it by placing the character c
inside all the matrix cells.
to visit the matrix use for in range cycles
Ingredients:
find matrix dimension
two nested fors
use range
NOTE: This function returns nothing!
If in the function text it is not mentioned to return values, DO NOT place the return
. If by chance you put it anyway it is not the world’s end, but to avoid confusion is much better having a behaviour consistent with the text.
[34]:
def fillc(mat, c):
raise Exception('TODO IMPLEMENT ME !')
m1 = [ ['a'] ]
m2 = [ ['z'] ]
fillc(m1,'z')
assert m1 == m2
m3 = [ ['a'] ]
m4 = [ ['y'] ]
fillc(m3,'y')
assert m3 == m4
m5 = [ ['a','b'] ]
m6 = [ ['z','z'] ]
fillc(m5,'z')
assert m5 == m6
m7 = [ ['a','b','c'],
['d','e','f'],
['g','h','i'] ]
m8 = [ ['y','y','y'],
['y','y','y'],
['y','y','y'] ]
fillc(m7,'y')
assert m7 == m8
# j 0 1
m9 = [ ['a','b'], # 0
['c','d'], # 1
['e','f'] ] # 2
m10 = [ ['x','x'], # 0
['x','x'], # 1
['x','x'] ] # 2
fillc(m9, 'x')
assert m9 == m10
fillx
✪✪ Takes a matrix mat as list of lists and a column index j
, and MODIFIES mat
by placing the 'x'
character in all cells of the j
-th column.
Example:
m = [
['a','b','c','d'],
['e','f','g','h'],
['i','l','m','n']
]
After the call to
fillx(m,2)
the matrix m
will be changed like this:
>>> print(m)
[
['a','b','x','d'],
['e','f','x','h'],
['i','l','x','n']
]
[35]:
def fillx(mat, j):
raise Exception('TODO IMPLEMENT ME !')
m1 = [ ['a'] ]
fillx(m1,0)
assert m1 == [ ['x'] ]
m2 = [ ['a','b'],
['c','d'],
['e','f'] ]
fillx(m2,0)
assert m2 == [ ['x','b'],
['x','d'],
['x','f'] ]
m3 = [ ['a','b'],
['c','d'],
['e','f'] ]
fillx(m3,1)
assert m3 == [ ['a','x'],
['c','x'],
['e','x'] ]
m4 = [ ['a','b','c','d'],
['e','f','g','h'],
['i','l','m','n'] ]
fillx(m4,2)
assert m4 == [ ['a','b','x','d'],
['e','f','x','h'],
['i','l','x','n'] ]
fillz
✪✪ Takes a matrix mat
as list of lists and a row index i
, and MODIFIES mat
by placing the character 'z'
in all the cells of the i
-th row.
Example:
m = [
['a','b'],
['c','d'],
['e','f'],
['g','h']
]
After the call to
>>> fillz(m,2)
the matrix m
will be changed like so:
>>> print(m)
[
['a','b'],
['c','d'],
['z','z'],
['g','h']
]
[36]:
def fillz(mat, i):
raise Exception('TODO IMPLEMENT ME !')
m1 = [ ['a'] ]
fillz(m1,0)
assert m1 == [ ['z'] ]
m2 = [ ['a','b'],
['c','d'],
['e','f'] ]
fillz(m2,0)
assert m2 == [ ['z','z'],
['c','d'],
['e','f'] ]
m3 = [ ['a','b'],
['c','d'],
['e','f'] ]
fillz(m3,1)
assert m3 == [ ['a','b'],
['z','z'],
['e','f'] ]
m4 = [ ['a','b'],
['c','d'],
['e','f'] ]
fillz(m4,2)
assert m4 == [ ['a','b'],
['c','d'],
['z','z'] ]
stitch_down
✪✪ Given matrices mat1
and mat2
as list of lists, with mat1 of size u
x n
and mat2
of size d
x n
, RETURN a NEW matrix of size (u
+d
) x n
as list of lists, by stitching second mat to the bottom of mat1
NOTE: by NEW matrix we intend a matrix with no pointers to original rows (see previous deep clone exercise)
for examples, see asserts
[37]:
def stitch_down(mat1, mat2):
raise Exception('TODO IMPLEMENT ME !')
m1 = [ ['a'] ]
m2 = [ ['b'] ]
assert stitch_down(m1, m2) == [ ['a'],
['b'] ]
# check we are giving back a deep clone
s = stitch_down(m1, m2)
s[0][0] = 'z'
assert m1[0][0] == 'a'
m1 = [ ['a','b','c'],
['d','b','a'] ]
m2 = [ ['f','b', 'h'],
['g','h', 'w'] ]
assert stitch_down(m1, m2) == [ ['a','b','c'],
['d','b','a'],
['f','b','h'],
['g','h','w'] ]
stitch_up
✪✪ Given matrices mat1
and mat2
as list of lists, with mat1
of size u
x n
and mat2
of size d
x n
, RETURN a NEW matrix of size (u
+d
) x n
as list of lists, by stitching first mat to the bottom of mat2
NOTE: by NEW matrix we intend a matrix with no pointers to original rows (see previous
deep_clone
exercise)To implement this function, use a call to the method stitch_down you implemented before.
For examples, see assert
[38]:
def stitch_up(mat1, mat2):
raise Exception('TODO IMPLEMENT ME !')
m1 = [ ['a'] ]
m2 = [ ['b'] ]
assert stitch_up(m1, m2) == [ ['b'],
['a'] ]
# check we are giving back a deep clone
s = stitch_up(m1, m2)
s[0][0] = 'z'
assert m1[0][0] == 'a'
m1 = [ ['a','b','c'],
['d','b','a'] ]
m2 = [ ['f','b', 'h'],
['g','h', 'w'] ]
assert stitch_up(m1, m2) == [ ['f','b','h'],
['g','h','w'],
['a','b','c'],
['d','b','a'] ]
stitch_right
✪✪✪ Given matrices mata
and matb
as list of lists, with mata
of size n
x l
and matb
of size n
x r
, RETURN a NEW matrix of size n
x (l
+ r
) as list of lists, by stitching second matb
to the right end of mata
[39]:
def stitch_right(mata,matb):
raise Exception('TODO IMPLEMENT ME !')
ma1 = [ ['a','b','c'],
['d','b','a'] ]
mb1 = [ ['f','b'],
['g','h'] ]
assert stitch_right(ma1, mb1) == [ ['a','b','c','f','b'],
['d','b','a','g','h'] ]
insercol
✪✪ Given a matrix mat
as list of lists, a column index j
and a list new_col
, write a function insercol(mat,j,new_col)
which MODIFIES mat
inserting the new column at position j
.
Example - given:
[40]:
# 0 1 2
m = [
[5,4,6],
[4,7,1],
[3,2,6],
]
By calling
>>> insercol(m, 2, [7,9,3])
m
will be MODIFIED with the insertion of column [7,9,3]
at position j=2
>>> m
# 0 1 2 3
[
[5,4,7,6],
[4,7,9,1],
[3,2,3,6],
]
for other examples, see asserts
HINT: lists already have a handy method
.insert
, so there is isn’t much code to write, just write the right one ;-)
[41]:
def insercol(mat, j, nuova_col):
raise Exception('TODO IMPLEMENT ME !')
m1 = [
[5]
]
assert insercol(m1,1,[8]) == None # the function returns nothing!
assert m1 == [ [5,8] ]
m2 = [ [5] ]
insercol(m2,0,[8])
assert m2 == [ [8,5] ]
m3 = [ [5,4,2],
[8,9,3] ]
insercol(m3,1,[7,6])
assert m3 == [ [5,7,4,2],
[8,6,9,3] ]
m4 = [ [5,4,6],
[4,7,1],
[3,2,6] ]
insercol(m4, 2, [7,9,3])
assert m4 == [ [5,4,7,6],
[4,7,9,1],
[3,2,3,6] ]
threshold
✪✪ Takes a matrix as a list of lists (every list has the same dimension) and RETURN a NEW matrix as list of lists where there is True
if the corresponding input element is greater than t
, otherwise return False
Ingredients:
a variable for the matrix to return
for each original row, we need to create a new list
[42]:
def threshold(mat, t):
raise Exception('TODO IMPLEMENT ME !')
morig = [ [1,4,2],
[7,9,3] ]
m1 = [ [1,4,2],
[7,9,3] ]
r1 = [ [False,False,False],
[True,True,False] ]
assert threshold(m1,4) == r1
assert m1 == morig # verify original didn't change
m2 = [ [5,2],
[3,7] ]
r2 = [ [True,False],
[False,True] ]
assert threshold(m2,4) == r2
swap_rows
✪✪ We will try swapping a couple of rows of a matrix
There are several ways to proceed. Before continuing, make sure to know how to exchange two values by solving this simple exercise - check your result in Python Tutor
Show solution[43]:
x = 3
y = 7
# write here the code to swap x and y (do not directly use the constants 3 and 7!)
✪✪ Takes a matrix mat
as list of lists, and RETURN a NEW matrix where rows at indexes i1
and i2
are swapped
[44]:
def swap_rows(mat, i1, i2):
raise Exception('TODO IMPLEMENT ME !')
m1 = [ ['a','d'],
['b','e'],
['c','f'] ]
r1 = swap_rows(m1, 0, 2)
assert r1 == [ ['c','f'],
['b','e'],
['a','d'] ]
r1[0][0] = 'z'
assert m1[0][0] == 'a'
m2 = [ ['a','d'],
['b','e'],
['c','f'] ]
# swap with itself should in fact generate a deep clone
r2 = swap_rows(m2, 0, 0)
assert r2 == [ ['a','d'],
['b','e'],
['c','f'] ]
r2[0][0] = 'z'
assert m2[0][0] == 'a'
swap_cols
✪✪ Takes a matrix mat
and two column indeces j1
and j2
and RETURN a NEW matrix where the columns j1
and j2
are swapped
[45]:
def swap_cols(mat, j1, j2):
raise Exception('TODO IMPLEMENT ME !')
m1 = [ ['a','b','c'],
['d','e','f'] ]
r1 = swap_cols(m1, 0,2)
assert r1 == [ ['c','b','a'],
['f','e','d'] ]
r1[0][0] = 'z'
assert m1[0][0] == 'a'
Continue
Go on with Matrices 2 - other exercises
[ ]: