Matrici - Liste di liste 1 - Introduzione
Scarica zip esercizi
ATTENZIONE
Gli esercizi che seguono contengono dei test con gli assert. Per capire come svolgerli, leggi prima Gestione errori e testing
Ci sono sostanzialmente due modi in Python di rappresentare matrici: come liste di liste, oppure con la libreria esterna numpy. La più usata è sicuramente numpy ma noi tratteremo comunque entrambi i modi. Vediamo il motivo e le principali differenze:
Liste di liste - esercizi in questo foglio:
native in Python
non efficienti
le liste sono pervasive in Python, probabilmente incontrerai matrici espresse come liste di liste in ogni caso
forniscono un’idea di come costruire una struttura dati annidata
possono servire per comprendere concetti importanti come puntatori alla memoria e copie
Numpy - vedere foglio separato Matrici Numpy:
non nativamente disponibile in Python
efficiente
alla base di parecchie librerie di calcolo scientifico (scipy, pandas)
la sintassi per accedere agli elementi è lievemente diversa da quella delle liste di liste
in alcuni rari casi potrebbe portare problemi di installazione e/o conflitti (l’implementazione non è puro Python)
Che fare
scompatta lo zip in una cartella, dovresti ottenere qualcosa del genere:
matrices-lists
matrices-lists1.ipynb
matrices-lists1-sol.ipynb
matrices-lists2.ipynb
matrices-lists2-sol.ipynb
matrices-lists3-chal.ipynb
jupman.py
ATTENZIONE: Per essere visualizzato correttamente, il file del notebook DEVE essere nella cartella szippata.
apri il Jupyter Notebook da quella cartella. Due cose dovrebbero aprirsi, prima una console e poi un browser. Il browser dovrebbe mostrare una lista di file: naviga la lista e apri il notebook
matrices-lists1.ipynb
Prosegui leggendo il file degli esercizi, ogni tanto al suo interno troverai delle scritte ESERCIZIO, che ti chiederanno di scrivere dei comandi Python nelle celle successive.
ATTENZIONE: Ricordati di eseguire sempre la prima cella dentro il notebook. Contiene delle istruzioni come import jupman
che dicono a Python quali moduli servono e dove trovarli. Per eseguirla, vedi le seguenti scorciatoie
Scorciatoie da tastiera:
Per eseguire il codice Python dentro una cella di Jupyter, premi
Control+Invio
Per eseguire il codice Python dentro una cella di Jupyter E selezionare la cella seguente, premi
Shift+Invio
Per eseguire il codice Python dentro una cella di Jupyter E creare una nuova cella subito dopo, premi
Alt+Invio
Se per caso il Notebook sembra inchiodato, prova a selezionare
Kernel -> Restart
Le celle in memoria
Vediamo queste liste di liste. Per esempio, possiamo considerare la seguente matrice con 3 righe e 2 colonne, in breve una matrice 3x2:
[2]:
m = [
['a','b'],
['c','d'],
['a','e']
]
Per convenienza, assumiamo come input per le nostre funzioni non ci saranno matrici senza righe, o righe senza colonne.
Tornando all’esempio, in pratica abbiamo una grande matrice esterna:
m = [
]
e ciascuno dei suoi elementi è un’altra lista che rappresenta una riga:
m = [
['a','b'],
['c','d'],
['a','e']
]
Quindi, per accedere la prima riga['a','b']
, semplicemente accediamo all’elemento all’indice 0 della lista esterna m
:
[3]:
m[0]
[3]:
['a', 'b']
Per accedere alla seconda riga intera ['c','d']
, accediamo all’elemento avete indice 1 della lista esterna m
:
[4]:
m[1]
[4]:
['c', 'd']
Per accedere alla terza riga intera ['c', 'd']
, accediamo all’elemento ad indice 2 della lista esterna m
:
[5]:
m[2]
[5]:
['a', 'e']
Per accedere al primo elemento 'a'
della prima riga ['a','b']
aggiungiamo un altro cosiddetto “subscript operator” con indice 0
:
[6]:
m[0][0]
[6]:
'a'
Per accedere il secondo elemento 'b'
della prima riga ['a','b']
usiamo invece indice 1
:
[7]:
m[0][1]
[7]:
'b'
ATTENZIONE: Quando una matrice è una lista di liste, puoi solo accedere valori con notazione m[i][j]
, NON con m[i,j]
!!
[8]:
# scrivi qui la notazione sbagliata m[0,0] e guarda che errore ottieni:
Dimensioni della matrice
✪ ESERCIZIO: Per prendere le dimensioni della matrice, possiamo usare normali operazioni su lista. Quali? Puoi assumere che la matrice sia ben formata (tutte le righe hanno lunghezza uguale) e almeno una riga e almeno una colonna.
[9]:
m = [
['a','b'],
['c','d'],
['a','e']
]
[10]:
# scrivi qui il codice per stampare righe e colonne
righe
3
colonne
2
Visitare con stile
Supponi che vogliamo visitare le celle di una matrice da sinistra a destra, e stamparle una per una.
Se vogliamo anche tenere traccia delle coordinate dove siamo durante la traversata, potremmo usare due for in range
annidati come questi:
[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("FINE RIGA!")
i: 0 j: 0 m[i][j]: a
i: 0 j: 1 m[i][j]: b
i: 0 j: 2 m[i][j]: c
FINE RIGA!
i: 1 j: 0 m[i][j]: d
i: 1 j: 1 m[i][j]: e
i: 1 j: 2 m[i][j]: f
FINE RIGA!
i: 2 j: 0 m[i][j]: g
i: 2 j: 1 m[i][j]: h
i: 2 j: 2 m[i][j]: i
FINE RIGA!
i: 3 j: 0 m[i][j]: m
i: 3 j: 1 m[i][j]: n
i: 3 j: 2 m[i][j]: o
FINE RIGA!
L’algoritmo è abbastanza semplice, ma notiamo un paio di cose:
abbiamo usato
i
come indice intero per le righeabbiamo usato
j
come indice intero per le colonne
Quei nomi e tipi sono importanti perchè di fatto sono standard nei libri di matematica.
Potresti facilmente bollare queste scelte come pura questione di stile, ma attenzione:
CON LE MATRICI, LO STILE *E’* SOSTANZA
Ti preghiamo di adottare lo stile di nomenclatura descritto sopra.
Coloro che non lo fanno, spesso perdono tempo nel temuto Debugging Hell…
Domanda - Questione di stile 1
Guarda il codice seguente che di nuovo stampa delle celle da sinistra a destra (supponi non ci curiamo di stampare le coordinate).
E’ scritta con stile? Perchè?
[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("FINE RIGA!")
a
b
c
FINE RIGA!
d
e
f
FINE RIGA!
g
h
i
FINE RIGA!
m
n
o
FINE RIGA!
Domanda - Questione di stile 2
Guarda il codice seguente che di nuovo stampa delle celle da sinistra a destra (supponi non ci curiamo di stampare le coordinate).
E’ scritta con stile? Perchè?
[13]:
m = [
['a','b','c'],
['d','e','f'],
['g','h','i'],
['m','n','o'],
]
for riga in range(len(m)):
for colonna in range(len(m[0])):
print(m[riga][colonna])
print("FINE RIGA!")
a
b
c
FINE RIGA!
d
e
f
FINE RIGA!
g
h
i
FINE RIGA!
m
n
o
FINE RIGA!
Domanda - Questione di stile 3
Guarda il codice seguente che di nuovo stampa delle celle da sinistra a destra (supponi non ci curiamo di stampare le coordinate).
E’ scritta con stile? Perchè?
[14]:
m = [
['a','b','c'],
['d','e','f'],
['g','h','i'],
['m','n','o'],
]
for riga in m:
for cella in riga:
print(cella)
print("FINE RIGA!")
a
b
c
FINE RIGA!
d
e
f
FINE RIGA!
g
h
i
FINE RIGA!
m
n
o
FINE RIGA!
Come risolvere gli esercizi
Tutti gli esercizi che seguono sono proposti come funzioni da implementare.
RICORDA: se la cella è eseguita e non succede niente, è perchè tutti i test degli assert sono passati ! In questo caso il tuo codice è probabilmente corretto ma attenzione, questo tipo di test non sono mai esaustivi perciò potrebbero comunque esserci errori.
III COMANDAMENTO: Non riassegnerai mai parametri di funzione
VI COMANDAMENTO: Userai il comando return
solo se vedi scritto RITORNA nella descrizione della funzione!
Estrarre righe e colonne
Come estrarre una riga
Una delle prime cose che potresti voler fare è estrarre la riga i-esima. Se stai implementando una funzione che fa questo, hai in sostanza due scelte:
ritornare un puntatore alla riga originale
ritornare una copia della riga
Dato che copiare consuma memoria, perchè vorresti mai ritornare una copia ? A volte dovresti perchè non sai quale uso verrà fatto della struttura dati. Per esempio, supponi di avere un libro di esercizi che ha spazi vuoti dove scrivere gli esercizi. E’ un libro eccellente, e tutti in classe lo vogliono leggere - ma tu sei preoccupato perchè se il libro comincia a cambiare mani qualche studente poco scrupoloso potrebbe scriverci sopra. Per evitare problemi, fai una copia del libro e la distribuisci (tralasciamo considerazioni sulla violazione del copyright :-)
Estrarre puntatori
Prima vediamo cosa succede quando ritorni semplicemente un puntatore alla riga originale.
NOTA: Per convenienza, alla fine della cella mettiamo una chiamata magica a jupman.pytut()
che mostra l’esecuzione di codice come in Python tutor (per info addizionali su jupman.pytut()
, vedere qua). Se esegui tutto il codice in Python Tutor, vedrai che alla fine hai due puntatori freccia alla riga ['a','b']
, uno che parte dalla lista m
e uno dalla variabile riga
.
[16]:
def esrigap(mat, i):
""" RITORNA la riga i-esima da mat
"""
return mat[i]
m = [
['a','b'],
['c','d'],
['a','e']
]
riga = esrigap(m, 0)
jupman.pytut()
[16]:
Estrai riga con for
Cercheremo di implementare una versione che ritorna una copia della riga.
DOMANDA: Per farlo, potresti essere tentato di scrivere qualcosa del genere - ma non funzionerebbe. Perchè?
[17]:
# ATTENZIONE: CODICE SBAGLIATO!!!!
def esriga_sbagliata(mat, i):
""" RITORNA la i-esima riga da mat. NOTA: la riga DEVE essere in una NUOVA lista ! """
riga = []
riga.append(mat[i])
return riga
m = [ ['a','b'],
['c','d'],
['a','e'] ]
riga = esriga_sbagliata(m,0)
jupman.pytut()
[17]:
Puoi costruire una copia in diversi modi, con un for
, una slice o una list comprehension. Prova ad implementare tutte le versioni, cominciando con il for
qui. Assicurati di controllare il risultato con Python tutor - per visualizzare Python tutor nell’output di una cella puoi usare il comando speciale jupman.pytut()
alla fine della cella come abbiamo fatto prima. In Python tutor, dovresti vedere solo una freccia che va dalla riga originale ['a','b']
in m
, e ci dovrebbe
essere un’altra copia ['a','b']
da qualche parte, con la variabile with riga
che ci punta.
Esercizio - esrigaf
✪ Implementa la funzione esrigaf
, che RITORNA la i
-esima riga da mat
come NUOVA lista
NOTA: Per creare una NUOVA lista usa un ciclo for che reitera sugli elementi, non gli indici (quindi non usare range) !
[18]:
def esrigaf(mat, i):
raise Exception('TODO IMPLEMENT ME !')
m = [ ['a','b'],
['c','d'],
['a','e'] ]
assert esrigaf(m, 0) == ['a','b']
assert esrigaf(m, 1) == ['c','d']
assert esrigaf(m, 2) == ['a','e']
# controlla che non abbia cambiato la matrice originale!
r = esrigaf(m, 0)
r[0] = 'z'
assert m[0][0] == 'a'
# togli il commento se vuoi visualizzare l'esecuzione qui
#jupman.pytut()
Estrai riga con range
Vediamo velocemente range(n)
. Forse pensi che debba ritornare una sequenza di interi, da zero a n - 1
. E’ davvero così?
[19]:
range(5)
[19]:
range(0, 5)
Forse ti aspettavi qualcosa come una lista [0,1,2,3,4]
, invece abbiamo scoperto che Python è piuttosto pigro qua: range(n)
di fatto ritorna un oggetto iterabile, non una sequenza reale materializzata in memoria.
Per prendere una vera lista di interi, dobbiamo chiedere esplicitamente questo oggetto iterabile che ci da gli oggetti uno per uno.
Quando scrivi for i in range(5)
il ciclo for
sta facendo esattamente questo, ad ogni round chiede all’oggetto range di generare un numero nella sequenza. Se vogliamo l’intera sequenza materializzata in memoria, possiamo generarla convertendo il range in un oggetto lista:
[20]:
list(range(5))
[20]:
[0, 1, 2, 3, 4]
Sii prudente, comunque. A seconda della dimensione della sequenza, questo potrebbe essere pericoloso. Una lista di un miliardo di elementi potrebbe saturare la RAM del tuo computer (i portatili nel 2018 hanno spesso 4 gigabyte di memoria RAM, cioè 4 miliardi di byte).
Esercizio - esrigar
✪ Adesso implementa la funzione esrigar
, che RITORNA la i
-esima riga da mat
come NUOVA lista, iterando su un range di indici di colonna
NOTA 1: Per creare una nuova lista usa un ciclo
for
NOTA 2: ricordati di usare un nuovo nome per l’indice di colonna!
[21]:
def esrigar(mat, i):
raise Exception('TODO IMPLEMENT ME !')
m = [
['a','b'],
['c','d'],
['a','e'],
]
assert esrigar(m, 0) == ['a','b']
assert esrigar(m, 1) == ['c','d']
assert esrigar(m, 2) == ['a','e']
# controlla che non abbia cambiato la matrice originale!
r = esrigar(m, 0)
r[0] = 'z'
assert m[0][0] == 'a'
# togli il commento se vuoi visualizzare l'esecuzione qui
#jupman.pytut()
Esercizio - Estrai riga con slice
✪ Ricordi che le slice ritornano una copia di una lista? Adesso prova ad usarle.
Implementa esrigas
, che RITORNA la i
-esima riga da mat
come NUOVA lista.
NOTA: Per crearla, usa le slice
[22]:
def esrigas(mat, i):
raise Exception('TODO IMPLEMENT ME !')
m = [
['a','b'],
['c','d'],
['a','e'],
]
assert esrigas(m, 0) == ['a','b']
assert esrigas(m, 1) == ['c','d']
assert esrigas(m, 2) == ['a','e']
# Controlla che non abbia cambiato la matrice originale !
r = esrigas(m, 0)
r[0] = 'z'
assert m[0][0] == 'a'
# togli il commento se vuoi visualizzare l'esecuzione qui
#jupman.pytut()
Esercizio - Estrai riga con list comprehension
✪ Implementa esrigac
, che RITORNA la i
-esima riga da mat
come NUOVA lista, creandola con le list comprehension
[23]:
def esrigac(mat, i):
raise Exception('TODO IMPLEMENT ME !')
m = [
['a','b'],
['c','d'],
['a','e'],
]
assert esrigac(m, 0) == ['a','b']
assert esrigac(m, 1) == ['c','d']
assert esrigac(m, 2) == ['a','e']
# Controlla che non abbia cambiato la matrice originale !
r = esrigac(m, 0)
r[0] = 'z'
assert m[0][0] == 'a'
# togli il commento se vuoi visualizzare l'esecuzione qui
#jupman.pytut()
Esercizio - Estrai colonna con for
✪ Prova ad estrarre una colonna alla posizione j
-esima, in questo caso non abbiamo bisogno di pensare se ritornare un puntatore o una copia.
Implementa escolf
, che RITORNA la j
-esima colonna da mat
: per crearla, usa un ciclo for
[24]:
def escolf(mat, j):
raise Exception('TODO IMPLEMENT ME !')
m = [
['a','b'],
['c','d'],
['a','e'],
]
assert escolf(m, 0) == ['a','c','a']
assert escolf(m, 1) == ['b','d','e']
# Controlla che la colonna ritornata non modifichi m
c = escolf(m,0)
c[0] = 'z'
assert m[0][0] == 'a'
# togli il commento se vuoi visualizzare l'esecuzione qui
#jupman.pytut()
Esercizio - Estrai colonna con list comprehension
✪ Implementa escolc
, che RITORNA la j
-esima colonna da mat
: per crearla, usa una list comprehension.
[25]:
def escolc(mat, j):
raise Exception('TODO IMPLEMENT ME !')
m = [
['a','b'],
['c','d'],
['a','e'],
]
assert escolc(m, 0) == ['a','c','a']
assert escolc(m, 1) == ['b','d','e']
# Controlla che la colonna ritornata non modifichi m
c = escolc(m,0)
c[0] = 'z'
assert m[0][0] == 'a'
# togli il commento se vuoi visualizzare l'esecuzione qui
#jupman.pytut()
Creare nuove matrici
Esercizio - matrice_vuota
✪✪ Ci sono diversi modi di creare una nuova matrice 3x5 vuota come lista di liste che contengono degli zero.
Implementa matrice_vuota
, che RITORNA una NUOVA matrice nxn come lista di liste riempite con zero
usa due cicli
for
annidati
[26]:
def matrice_vuota(n, m):
raise Exception('TODO IMPLEMENT ME !')
assert matrice_vuota(1,1) == [ [0] ]
assert matrice_vuota(1,2) == [ [0,0] ]
assert matrice_vuota(2,1) == [ [0],
[0] ]
assert matrice_vuota(2,2) == [ [0,0],
[0,0] ]
assert matrice_vuota(3,3) == [ [0,0,0],
[0,0,0],
[0,0,0] ]
matrice_vuota nel modo elegante
Per creare una lista di 3 elementi riempita di zeri, puoi scrivere così:
[27]:
[0]*3
[27]:
[0, 0, 0]
Il *
in un certo senso sta moltiplicando gli elementi in una lista
Dato quanto sopra, per creare una matrice 5x3 riempita di zeri, che è una lista di liste apparentemente uguali, potresti essere tentato di scrivere così:
[28]:
# SBAGLIATO !
[[0]*3]*5
[28]:
[[0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]]
Come mai questo è (probabilmente) sbagliato ? Prova a ispezionarlo in Python Tutor:
[29]:
bad = [[0]*3]*5
jupman.pytut()
[29]:
Se guardi da vicino, noterai parecchie frecce che puntano alla stessa lista di 3 zeri. Questo significa che se cambiamo un numero, apparentemente cambieremo 5 di loro nell’intera colonna !
Il modo giusto di creare una matrice come lista di liste con zeri è il seguente:
[30]:
# CORRETTO
[[0]*3 for i in range(5)]
[30]:
[[0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]]
Esercizio - vuota_eleg
✪ Prova a creare una matrice con 7 righe e 4 colonne e riempila di 5.
Mostra soluzione[31]:
# scrivi qui
[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]]
Copia in profondità
Vediamo come si può produrre un clone completo di una matrice, anche chiamato deep clone, creando una copia sia della lista esterna e anche delle liste interne che rappresentano le righe.
DOMANDA: Per farlo, potresti essere tentato di scrivere codice del genere, ma non funzionerà. Perchè?
[32]:
# ATTENZIONE: CODICE SBAGLIATO:
def deep_clone_sbagliato(mat):
""" RITORNA una NUOVA lista di liste che un DEEP CLONE di mat (che è una lista di liste)
"""
return mat[:]
m = [ ['a','b'],
['b','d'] ]
res = deep_clone_sbagliato(m)
jupman.pytut()
[32]:
Nel codice sopra, avrai bisogno di iterare attraverso le righe e per ciascuna riga creare una copia di quella riga.
Esercizio - deep_clone
✪✪ Implementa deep_clone
, che RITORNA una NUOVA lista come un DEEP CLONE completo di mat
(che è una lista di liste)
NOTA: L’esercizio si può risolvere molto velocemente usando la funzione deepcopy, ma ti invitiamo a provare a risolverlo senza.
Mostra soluzione[33]:
def deep_clone(mat):
raise Exception('TODO IMPLEMENT ME !')
m = [ ['a','b'],
['b','d'] ]
res = [ ['a','b'],
['b','d'] ]
# verifica la copia
c = deep_clone(m)
assert c == res
# verifica che una copia in profondità (cioè, ha anche creato cloni delle righe !)
c[0][0] = 'z'
assert m[0][0] == 'a'
Modificare matrici
Esercizio - riempic
✪✪ Implementa la funzione riempic
, che prende la matrice in input mat
(una lista di liste di dimensione nrighe
x ncol
) e la MODIFICA mettendo il carattere c
dentro tutte le celle della matrice.
per scorrere la matrice usa dei cicli for in range
Ingredienti:
trovare dimensioni matrice
due for annidati
usare range
NOTA : Questa funzione non ritorna nulla!
Se nel testo della funzione non viene menzionato di tornare dei valori, NON bisogna mettere il return
. Se per caso lo si mette lo stesso non casca il mondo, ma per evitare confusione è molto meglio avere un comportamento consistente col testo.
[34]:
def riempic(mat, c):
raise Exception('TODO IMPLEMENT ME !')
m1 = [ ['a'] ]
m2 = [ ['z'] ]
riempic(m1,'z')
assert m1 == m2
m3 = [ ['a'] ]
m4 = [ ['y'] ]
riempic(m3,'y')
assert m3 == m4
m5 = [ ['a','b'] ]
m6 = [ ['z','z'] ]
riempic(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'] ]
riempic(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
riempic(m9, 'x')
assert m9 == m10
Esercizio - riempix
✪✪ Prende una matrice mat
come lista di liste e un indice di colonna j
, e MODIFICA mat
mettendo il carattere 'x'
in tutte le celle della colonna j
-esima.
Esempio:
m = [
['a','b','c','d'],
['e','f','g','h'],
['i','l','m','n']
]
Dopo la chiamata a
riempix(m,2)
la matrice m
sarà cambiata così:
print(m)
[
['a','b','x','d'],
['e','f','x','h'],
['i','l','x','n']
]
[35]:
def riempix(mat, j):
raise Exception('TODO IMPLEMENT ME !')
m1 = [ ['a'] ]
riempix(m1,0)
assert m1 == [ ['x'] ]
m2 = [ ['a','b'],
['c','d'],
['e','f'] ]
riempix(m2,0)
assert m2 == [ ['x','b'],
['x','d'],
['x','f'] ]
m3 = [ ['a','b'],
['c','d'],
['e','f'] ]
riempix(m3,1)
assert m3 == [ ['a','x'],
['c','x'],
['e','x'] ]
m4 = [ ['a','b','c','d'],
['e','f','g','h'],
['i','l','m','n'] ]
riempix(m4,2)
assert m4 == [ ['a','b','x','d'],
['e','f','x','h'],
['i','l','x','n'] ]
Esercizio - riempiz
✪✪ Prende una matrice mat
come lista di liste e un indice di riga i
, e MODIFICA mat
mettendo il carattere 'z'
in tutte le celle della riga i
-esima.
Esempio:
m = [
['a','b'],
['c','d'],
['e','f'],
['g','h']
]
Dopo la chiamata a
>>> riempiz(m,2)
la matrice m
sarà cambiata così:
>>> print(m)
[
['a','b'],
['c','d'],
['z','z'],
['g','h']
]
[36]:
def riempiz(mat, i):
raise Exception('TODO IMPLEMENT ME !')
m1 = [ ['a'] ]
riempiz(m1,0)
assert m1 == [ ['z'] ]
m2 = [ ['a','b'],
['c','d'],
['e','f'] ]
riempiz(m2,0)
assert m2 == [ ['z','z'],
['c','d'],
['e','f'] ]
m3 = [ ['a','b'],
['c','d'],
['e','f'] ]
riempiz(m3,1)
assert m3 == [ ['a','b'],
['z','z'],
['e','f'] ]
m4 = [ ['a','b'],
['c','d'],
['e','f'] ]
riempiz(m4,2)
assert m4 == [ ['a','b'],
['c','d'],
['z','z'] ]
Esercizio - attacca_sotto
✪✪ Date le matrici mat1
e mat2
come lista di liste, con mat1
di dimensione u
x n
e mat2
di dimensione d
x n
, RITORNA una NUOVA matrice di dimensione (u
+d
) x n
come lista di liste, attaccando la seconda matrice in fondo a mat1
NOTA: per NUOVA matrice intendiamo una matrice con nessun puntatore alle righe originali (vedi il precedente esercizio deep_clone)
Per esempi, vedere gli assert
[37]:
def attacca_sotto(mat1, mat2):
raise Exception('TODO IMPLEMENT ME !')
m11 = [ ['a'] ]
m12 = [ ['b'] ]
assert attacca_sotto(m11, m12) == [ ['a'],
['b'] ]
# controlla che non stiamo dando indietro un deep clone
r = attacca_sotto(m11, m12)
r[0][0] = 'z'
assert m11[0][0] == 'a'
m21 = [ ['a','b','c'],
['d','b','a'] ]
m22 = [ ['f','b', 'h'],
['g','h', 'w'] ]
assert attacca_sotto(m21, m22) == [ ['a','b','c'],
['d','b','a'],
['f','b','h'],
['g','h','w'] ]
Esercizio - attacca_sopra
✪✪ Date le matrici mat1
e mat2
come lista di liste, con mat1
di dimensione u
x n
e mat2
di dimensione d
x n
, RITORNA una NUOVA matrice di dimensione (u
+d
) x n
come lista di liste, attaccando la prima mat
alla fine di mat2
NOTA: per NUOVA matrice intendiamo una matrice con nessun puntatore alle righe originali (vedi il precedente esercizio
deep_clone
)Per implementare questa funzione, usa una chiamata al metodo attacca_sotto che hai implementato prima
Per esempi, vedere gli assert
[38]:
def attacca_sopra(mat1, mat2):
raise Exception('TODO IMPLEMENT ME !')
m1 = [ ['a'] ]
m2 = [ ['b'] ]
assert attacca_sopra(m1, m2) == [ ['b'],
['a'] ]
# controlla che stiamo ritornando un deep clone
s = attacca_sopra(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 attacca_sopra(m1, m2) == [ ['f','b','h'],
['g','h','w'],
['a','b','c'],
['d','b','a'] ]
Esercizio - attacca_dx
✪✪✪ Date le matrici mat1
e mat2
come lista di liste, con mat1
di dimensione n
x l
e mat2
di dimensione n
x r
, RITORNA una NUOVA matrice di dimensione n
x (l
+ r
) come lista di liste, attaccando mat2
alla destra di mat1
[39]:
def attacca_dx(mat1,mat2):
raise Exception('TODO IMPLEMENT ME !')
m1 = [ ['a','b','c'],
['d','b','a'] ]
m2 = [ ['f','b'],
['g','h'] ]
assert attacca_dx(m1, m2) == [ ['a','b','c','f','b'],
['d','b','a','g','h'] ]
Esercizio - insercol
✪✪ Data una matrice mat
come lista di liste, un indice di colonna j
e una lista nuova_col
, scrivere una funzione insercol(mat,j, nuova_col)
che MODIFICA mat
inserendo alla posizione j
la nuova colonna.
Esempio - data:
[40]:
# 0 1 2
m = [
[5,4,6],
[4,7,1],
[3,2,6],
]
Chiamando
>>> insercol(mat, 2, [7,9,3])
m
sarà MODIFICATA con l’inserimento della colonna [7,9,3]
alla posizione j=2
>>> m
# 0 1 2 3
[
[5,4,7,6],
[4,7,9,1],
[3,2,3,6],
]
per altri esempi, vedere gli assert
SUGGERIMENTO: le liste hanno già un comodo metodo
.insert
, quindi non c’è tanto codice da scrivere, basta scrivere quello giusto ;-)
[41]:
def insercol(mat, j, nuova_col):
raise Exception('TODO IMPLEMENT ME !')
m1 = [
[5]
]
assert insercol(m1,1,[8]) == None # la funzione non ritorna nulla !
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] ]
Esercizio - remcol
Data una matrice mat come lista di liste, MODIFICA mat rimuovendo la colonna j-esima, e RITORNA una lista con tutti i valori rimossi
Se
j
è negativo o maggiore della larghezza della matrice, sollevaValueError
NOTA: è un po’ particolare perchè sia MODIFICA che RITORNA
Esempio:
>>> m = [ [5,4,7,6],
[4,7,9,1],
[3,2,3,6] ]
>>> remcol(m,2)
[7,9,3]
>>> print(m)
[ [5,4,6],
[4,7,1],
[3,2,6] ]
[42]:
def remcol(mat,j):
raise Exception('TODO IMPLEMENT ME !')
m1 = [ [5, 8] ]
assert remcol(m1,0) == [5]
assert m1 == [ [8] ]
m2 = [ [5, 8] ]
assert remcol(m2,1) == [8]
assert m2 == [ [5] ]
m3 = [ [7,2],
[9,4],
[6,1] ]
assert remcol(m3,0) == [7,9,6]
assert m3 == [ [2],
[4],
[1]]
m4 = [ [5,4,7,6],
[4,7,9,1],
[3,2,3,6] ]
assert remcol(m4,2) == [7,9,3]
assert m4 == [ [5,4,6],
[4,7,1],
[3,2,6] ]
m5 = [ [5,4,7,6],
[4,7,9,1],
[3,2,3,6] ]
assert remcol(m5,3) == [6,1,6]
assert m5 == [ [5,4,7],
[4,7,9],
[3,2,3] ]
m6 = [ [5,4,7,6],
[4,7,9,1],
[3,2,3,6] ]
try:
remcol(m6, -3)
except ValueError:
pass
try:
remcol(m6, 4)
except ValueError:
pass
Esercizio - soglia
✪✪ Prende una matrice mat
come lista di liste (ogni lista ha la stessa dimensione) e un numero t
, e RITORNA una NUOVA matrice come lista di liste dove c’è True
se l’elemento di input corrispondente è maggiore di t
, altrimenti ritorna False
.
Ingredienti:
una variabile per la matrice da ritornare
per ogni riga originale, dobbiamo creare una nuova lista
[43]:
def soglia(mat, t):
raise Exception('TODO IMPLEMENT ME !')
morig = [ [1,4,2],
[7,9,3] ]
m = [ [1,4,2],
[7,9,3] ]
s = [ [False,False,False],
[True, True, False] ]
assert soglia(m,4) == s
assert m == morig # verifica che original non sia cambiata
m = [ [5,2],
[3,7] ]
s = [
[True,False],
[False,True]
]
assert soglia(m,4) == s
Esercizio - scambia_righe
Proveremo a scambiare due righe di una matrice
Ci sono diversi modi di procedere. Prima di continuare, assicurati di sapere come scambiare solo due valori risolvendo questo semplice esercizio - controlla inoltre il risultato in Python Tutor.
Mostra soluzione[44]:
x = 3
y = 7
# scrivi qui il codice per scambiare x e y (non usare direttamente le costanti 3 e 7!)
✪✪ Prende una matrice mat
come lista di liste, e RITORNA una NUOVA matrice dove le righe agli indici i1
e i2
sono scambiate
Ingredienti:
prima clona in profondità
poi scambia le righe
[45]:
def scambia_righe(mat, i1, i2):
raise Exception('TODO IMPLEMENT ME !')
m = [ ['a','d'],
['b','e'],
['c','f'] ]
res = scambia_righe(m, 0, 2)
assert res == [ ['c','f'],
['b','e'],
['a','d'] ]
res[0][0] = 'z'
assert m[0][0] == 'a'
m = [ ['a','d'],
['b','e'],
['c','f'] ]
# scambia con se stesso dovrebbe nei fatti generare un deep clone
res = scambia_righe(m, 0, 0)
assert res == [ ['a','d'],
['b','e'],
['c','f'] ]
res[0][0] = 'z'
assert m[0][0] == 'a'
Esercizio - scambia_colonne
✪✪ Prende una matrice mat
e due indici di colonna j1
e j2
e RITORNA una NUOVA matrice dove le colonne j1
e j2
sono scambiate
[46]:
def scambia_colonne(mat, j1, j2):
raise Exception('TODO IMPLEMENT ME !')
m = [ ['a','b','c'],
['d','e','f'] ]
res = scambia_colonne(m, 0,2)
assert res == [ ['c','b','a'],
['f','e','d'] ]
res[0][0] = 'z'
assert m[0][0] == 'a'
Prosegui
Continua con Matrici 2 - altri esercizi