Aller au contenu
Réussir mon BTS SIO

Tape une notion, une commande ou le nom d'une épreuve.

Par exemple

Chapitre 825 minDébutant

Tableaux à deux dimensions, matrices et dictionnaires

Par Josselyn C., prof de BTS SIO. Mis à jour le .

À la fin de ce chapitre, tu sauras

  • construire et parcourir un tableau à deux dimensions ;
  • traiter une ligne ou une colonne, et programmer un produit matriciel ;
  • représenter des enregistrements avec des dictionnaires ;
  • lire un tableau de données dans un fichier CSV.

6 exercices corrigés1 schéma

Un tableau à deux dimensions est un tableau de lignes, dont chaque case est repérée par deux indices : le numéro de ligne et le numéro de colonne. En Python, on le représente par une liste de listes. Ce chapitre montre comment le construire, le parcourir ligne par ligne ou colonne par colonne, calculer un produit de matrices, gérer des colonnes de types différents, et utiliser les dictionnaires Python.

Un tableau de tableaux

Un professeur range les notes de trois étudiants dans quatre matières. Une ligne par étudiant, une colonne par matière :

Maths (0)Anglais (1)CEJM (2)Développement (3)
Inès (0)1215914
Hugo (1)8111310
Léa (2)16181217

En Python, chaque ligne est une liste, et le tableau est la liste de ces lignes :

python
notes = [
    [12, 15, 9, 14],   # Inès
    [8, 11, 13, 10],   # Hugo
    [16, 18, 12, 17],  # Léa
]
print(notes[2][1])        # ligne 2, colonne 1 : Léa en anglais
print(notes[1])           # la ligne 1 entière
print(len(notes), len(notes[0]))  # nombre de lignes, de colonnes
text
18
[8, 11, 13, 10]
3 4

notes[i] est la ligne i (une liste), et notes[i][j] la case de la ligne i et de la colonne j. La convention est toujours ligne d'abord, colonne ensuite. En pseudo-code, on écrit notes[i][j] ou notes[i, j], et on déclare notes : tableau[0..2][0..3] d'entiers.

0123i \ j0121591418111310216181217notes[1] : une lignenotes[2][1] : 18colonne 3 : notes[i][3]
Un tableau à deux dimensions : notes[i] est une ligne, notes[i][j] une case ; une colonne se lit avec une boucle sur i

Construire un tableau à deux dimensions

Pour créer un tableau de nb_lignes × nb_colonnes rempli de zéros, construis chaque ligne séparément, dans une boucle :

python
nb_lignes, nb_colonnes = 3, 4
grille = []
for i in range(nb_lignes):
    grille.append([0] * nb_colonnes)
grille[0][0] = 5
print(grille)
text
[[5, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]

Pour la même raison, copie = notes.copy() ne suffit pas à copier un tableau à deux dimensions : la liste extérieure est copiée, mais les lignes restent partagées. Copie chaque ligne : copie = [ligne.copy() for ligne in notes], ou avec deux boucles.

Parcourir toutes les cases

Deux boucles imbriquées : la boucle externe sur les lignes, la boucle interne sur les colonnes.

text
Pour i de 0 à nb_lignes - 1 Faire
    Pour j de 0 à nb_colonnes - 1 Faire
        Afficher(notes[i][j])
    FinPour
FinPour
python
notes = [[12, 15, 9, 14], [8, 11, 13, 10], [16, 18, 12, 17]]
for i in range(len(notes)):
    for j in range(len(notes[i])):
        print(notes[i][j], end=" ")
    print()
text
12 15 9 14 
8 11 13 10 
16 18 12 17 

Le maximum de tout le tableau, avec sa position, reprend le motif du chapitre 7 en deux dimensions :

python
notes = [[12, 15, 9, 14], [8, 11, 13, 10], [16, 18, 12, 17]]
i_max, j_max = 0, 0
for i in range(len(notes)):
    for j in range(len(notes[i])):
        if notes[i][j] > notes[i_max][j_max]:
            i_max, j_max = i, j
print("Max", notes[i_max][j_max], "en ligne", i_max, "colonne", j_max)
text
Max 18 en ligne 2 colonne 1

Traiter une ligne ou une colonne

Le programme demande de savoir « traiter les éléments d'une ligne ou d'une colonne ». Pour une ligne, on fixe i et on fait varier j ; pour une colonne, on fixe j et on fait varier i.

python
notes = [[12, 15, 9, 14], [8, 11, 13, 10], [16, 18, 12, 17]]
etudiants = ["Inès", "Hugo", "Léa"]
matieres = ["Maths", "Anglais", "CEJM", "Développement"]

# Moyenne de chaque étudiant : une ligne à la fois
for i in range(len(notes)):
    somme = 0
    for j in range(len(notes[i])):
        somme = somme + notes[i][j]
    print(etudiants[i], somme / len(notes[i]))

# Moyenne de chaque matière : une colonne à la fois
for j in range(len(matieres)):
    somme = 0
    for i in range(len(notes)):
        somme = somme + notes[i][j]
    print(matieres[j], round(somme / len(notes), 2))
text
Inès 12.5
Hugo 10.5
Léa 15.75
Maths 12.0
Anglais 14.67
CEJM 11.33
Développement 13.67

Remarque deux choses. L'accumulateur somme est réinitialisé au début de chaque ligne (ou colonne), à l'intérieur de la boucle externe. Et pour les colonnes, c'est la boucle sur j qui est à l'extérieur : l'ordre des boucles dépend de ce qu'on veut regrouper.

Matrices et produit matriciel

En maths, un tableau à deux dimensions de nombres est une matrice. Le programme demande de savoir programmer le produit de deux matrices, la formule étant donnée : si A a n lignes et p colonnes, et B a p lignes et m colonnes, le produit C = A × B a n lignes et m colonnes, et

c[i][j] = a[i][0] × b[0][j] + a[i][1] × b[1][j] + … + a[i][p−1] × b[p−1][j]

C'est une somme : chaque coefficient demande une boucle, et il y a n × m coefficients. D'où trois boucles imbriquées.

text
Fonction Produit(A, B : tableaux de réels) : tableau de réels
// Précondition : nombre de colonnes de A = nombre de lignes de B
    n ← nombre de lignes de A
    p ← nombre de colonnes de A
    m ← nombre de colonnes de B
    Pour i de 0 à n - 1 Faire
        Pour j de 0 à m - 1 Faire
            C[i][j] ← 0
            Pour k de 0 à p - 1 Faire
                C[i][j] ← C[i][j] + A[i][k] × B[k][j]
            FinPour
        FinPour
    FinPour
    Retourner C
FinFonction
python
def produit(A, B):
    n, p, m = len(A), len(B), len(B[0])
    C = []
    for i in range(n):
        ligne = []
        for j in range(m):
            somme = 0
            for k in range(p):
                somme = somme + A[i][k] * B[k][j]
            ligne.append(somme)
        C.append(ligne)
    return C


A = [[1, 2, 0],
     [3, -1, 4]]
B = [[2, 1],
     [0, 3],
     [5, -2]]
print(produit(A, B))
text
[[2, 7], [26, -8]]

Vérification d'un coefficient à la main : c[1][1] = 3 × 1 + (−1) × 3 + 4 × (−2) = 3 − 3 − 8 = −8. Le calcul matriciel (somme, transposée, inverse, puissances) est au cours de matrices. Les matrices servent aussi à représenter un graphe par sa matrice d'adjacence (chapitre 11).

Des colonnes de types différents

Le programme prévoit aussi des tableaux à deux dimensions dont les colonnes (ou les lignes) ont des types différents. C'est la forme d'un inventaire de parc : chaque ligne décrit un poste, chaque colonne une information.

Inventaire (0)Marque (1)Année (2)Prix d'achat (3)
"PC-001" (chaîne)"Dell" (chaîne)2021 (entier)649.0 (réel)
"PC-002""HP"2023799.0
"PC-003""Lenovo"2019520.0

Une liste Python accepte des types différents : chaque ligne peut être une liste, ou mieux un tuple (une séquence non modifiable, entre parenthèses), car la structure d'une ligne ne change pas.

python
parc = [
    ("PC-001", "Dell", 2021, 649.0),
    ("PC-002", "HP", 2023, 799.0),
    ("PC-003", "Lenovo", 2019, 520.0),
]
total = 0
for poste in parc:
    total = total + poste[3]
    if 2026 - poste[2] >= 5:
        print(poste[0], "a 5 ans ou plus : à renouveler")
print("Valeur d'achat du parc :", total)
text
PC-001 a 5 ans ou plus : à renouveler
PC-003 a 5 ans ou plus : à renouveler
Valeur d'achat du parc : 1968.0

C'est lisible tant qu'on se souvient que la colonne 3 est le prix. Avec dix colonnes, poste[7] ne veut plus rien dire : c'est là que les dictionnaires deviennent utiles.

Les dictionnaires Python

Un dictionnaire associe des clés à des valeurs. Au lieu d'un indice numérique, on accède à une valeur par sa clé, en général une chaîne. Les dictionnaires ne sont pas au programme de mathématiques (les structures de données relèvent des enseignements professionnels), mais tu les utiliseras sans cesse en SLAM comme en SISR, et le programme demande justement d'adapter la construction des tableaux aux possibilités de l'outil utilisé.

python
stock = {"clavier": 12, "souris": 0, "écran": 3}
print(stock["clavier"])          # accès par la clé
stock["webcam"] = 7              # ajout d'une paire
stock["écran"] = stock["écran"] + 10   # modification
del stock["souris"]              # suppression
print(stock)
print("souris" in stock)         # la clé existe-t-elle ?
print(stock.get("souris", 0))    # valeur par défaut si absente
for article, quantite in stock.items():
    print(article, ":", quantite)
text
12
{'clavier': 12, 'écran': 13, 'webcam': 7}
False
0
clavier : 12
écran : 13
webcam : 7
OpérationPythonAttention
Créerd = {} ou d = {"a": 1}Une clé n'apparaît qu'une fois
Lired["a"]KeyError si la clé n'existe pas
Lire sans risqued.get("a", 0)Renvoie 0 si la clé est absente
Ajouter ou modifierd["a"] = 2La même instruction fait les deux
Supprimerdel d["a"]KeyError si absente
Tester une clé"a" in dTeste les clés, pas les valeurs
Parcourirfor cle, valeur in d.items():Ordre d'insertion conservé

Le dictionnaire est parfait pour compter des occurrences, un exercice classique : chaque valeur rencontrée devient une clé, son compteur est la valeur.

python
statuts = ["ouvert", "résolu", "ouvert", "en cours", "résolu", "ouvert"]
compte = {}
for s in statuts:
    if s in compte:
        compte[s] = compte[s] + 1
    else:
        compte[s] = 1
print(compte)
text
{'ouvert': 3, 'résolu': 2, 'en cours': 1}

Une liste de dictionnaires donne un tableau dont chaque colonne a un nom. C'est exactement la forme des lignes renvoyées par une requête SQL dans une application, ou d'un fichier JSON :

python
parc = [
    {"inventaire": "PC-001", "marque": "Dell", "annee": 2021, "prix": 649.0},
    {"inventaire": "PC-002", "marque": "HP", "annee": 2023, "prix": 799.0},
    {"inventaire": "PC-003", "marque": "Lenovo", "annee": 2019, "prix": 520.0},
]
for poste in parc:
    if poste["marque"] == "HP":
        print(poste["inventaire"], poste["prix"])

poste["prix"] se lit sans commentaire, contrairement à poste[3]. Le cours de SQL montre l'autre façon de stocker ce genre de données, dans une base relationnelle.

Lire un tableau dans un fichier CSV

Les fichiers ne sont pas au programme de mathématiques, mais un tableau à deux dimensions vient souvent d'un fichier CSV exporté d'un tableur ou d'un outil de supervision. Chaque ligne du fichier est une ligne du tableau, et un séparateur (; dans les exports français) sépare les colonnes. Avec un fichier parc.csv :

text
inventaire;marque;annee;prix
PC-001;Dell;2021;649.0
PC-002;HP;2023;799.0
PC-003;Lenovo;2019;520.0
python
parc = []
with open("parc.csv", encoding="utf-8") as fichier:
    fichier.readline()                     # saute la ligne d'en-tête
    for ligne in fichier:
        champs = ligne.strip().split(";")  # découpe la ligne en colonnes
        parc.append((champs[0], champs[1], int(champs[2]), float(champs[3])))
print(parc)
text
[('PC-001', 'Dell', 2021, 649.0), ('PC-002', 'HP', 2023, 799.0), ('PC-003', 'Lenovo', 2019, 520.0)]

Tout ce qu'on lit dans un fichier est du texte : il faut convertir les colonnes numériques (int, float), comme après un input. strip() retire le retour à la ligne de fin, split(";") découpe (chapitre 9). Le bloc with ferme le fichier automatiquement. Pour des CSV plus complexes (champs entre guillemets contenant des ;), Python fournit le module csv.

Exercices

Exercice 1 sur 6 Indices Réussi À revoir

Avec t = [[4, 8, 1], [7, 2, 9], [3, 6, 5]], donne la valeur de : t[0][2], t[2][0], t[1], t[1][1] + t[2][2], len(t[0]). Quelle expression désigne la case contenant 6 ?

Voir la réponseMasquer la réponse de l'exercice 1

t[0][2] vaut 1, t[2][0] vaut 3, t[1] vaut [7, 2, 9], t[1][1] + t[2][2] vaut 2 + 5 = 7, len(t[0]) vaut 3. Le 6 est en ligne 2, colonne 1 : t[2][1].

Tu avais trouvé ?

Exercice 2 sur 6 Places libres Réussi À revoir

Le plan d'une salle de formation est un tableau de 3 rangées de 5 places : 1 pour une place occupée, 0 pour une place libre.

python
salle = [[1, 0, 0, 1, 1],
         [1, 1, 1, 1, 1],
         [0, 0, 1, 0, 0]]

Écris un programme qui affiche le nombre de places libres de chaque rangée, puis le total, puis le numéro de la première rangée complète (ou −1).

Voir la réponseMasquer la réponse de l'exercice 2
python
salle = [[1, 0, 0, 1, 1],
         [1, 1, 1, 1, 1],
         [0, 0, 1, 0, 0]]
total = 0
rangee_complete = -1
for i in range(len(salle)):
    libres = 0
    for j in range(len(salle[i])):
        if salle[i][j] == 0:
            libres = libres + 1
    print("Rangée", i, ":", libres, "place(s) libre(s)")
    total = total + libres
    if libres == 0 and rangee_complete == -1:
        rangee_complete = i
print("Total :", total)
print("Première rangée complète :", rangee_complete)
text
Rangée 0 : 2 place(s) libre(s)
Rangée 1 : 0 place(s) libre(s)
Rangée 2 : 4 place(s) libre(s)
Total : 6
Première rangée complète : 1

Le test rangee_complete == -1 garantit qu'on garde la première rangée complète, même s'il y en a plusieurs.

Tu avais trouvé ?

Exercice 3 sur 6 Transposée Réussi À revoir

La transposée d'une matrice M de n lignes et m colonnes est la matrice T de m lignes et n colonnes telle que T[j][i] = M[i][j]. Écris une fonction transposee(M) et teste-la sur [[1, 2, 3], [4, 5, 6]].

Voir la réponseMasquer la réponse de l'exercice 3
python
def transposee(M):
    n, m = len(M), len(M[0])
    T = []
    for j in range(m):
        ligne = []
        for i in range(n):
            ligne.append(M[i][j])
        T.append(ligne)
    return T


print(transposee([[1, 2, 3], [4, 5, 6]]))

Résultat : [[1, 4], [2, 5], [3, 6]]. Les lignes de M sont devenues les colonnes de T. La boucle externe porte sur les colonnes de M, puisque chacune devient une ligne de T.

Tu avais trouvé ?

Exercice 4 sur 6 Produit de matrices Réussi À revoir

Calcule à la main, puis avec la fonction produit du cours, le produit A × B avec A = [[2, 0], [1, 3]] et B = [[1, 4], [2, -1]]. Puis calcule B × A. Que remarques-tu ?

Voir la réponseMasquer la réponse de l'exercice 4

A × B : c[0][0] = 2 × 1 + 0 × 2 = 2 ; c[0][1] = 2 × 4 + 0 × (−1) = 8 ; c[1][0] = 1 × 1 + 3 × 2 = 7 ; c[1][1] = 1 × 4 + 3 × (−1) = 1. Résultat : [[2, 8], [7, 1]].

B × A : c[0][0] = 1 × 2 + 4 × 1 = 6 ; c[0][1] = 1 × 0 + 4 × 3 = 12 ; c[1][0] = 2 × 2 + (−1) × 1 = 3 ; c[1][1] = 2 × 0 + (−1) × 3 = −3. Résultat : [[6, 12], [3, -3]].

Les deux produits sont différents : le produit de matrices n'est pas commutatif. L'ordre des arguments de produit compte.

Tu avais trouvé ?

Exercice 5 sur 6 Le morpion Réussi À revoir

Une grille de morpion est un tableau 3 × 3 de chaînes "X", "O" ou " ". Écris une fonction gagne(grille, joueur) qui renvoie True si joueur a aligné trois symboles sur une ligne, une colonne ou une diagonale.

Voir la réponseMasquer la réponse de l'exercice 5
python
def gagne(grille, joueur):
    for i in range(3):
        # ligne i
        if grille[i][0] == joueur and grille[i][1] == joueur and grille[i][2] == joueur:
            return True
        # colonne i
        if grille[0][i] == joueur and grille[1][i] == joueur and grille[2][i] == joueur:
            return True
    # diagonales
    if grille[0][0] == joueur and grille[1][1] == joueur and grille[2][2] == joueur:
        return True
    if grille[0][2] == joueur and grille[1][1] == joueur and grille[2][0] == joueur:
        return True
    return False


g = [["X", "O", " "],
     ["O", "X", " "],
     ["O", " ", "X"]]
print(gagne(g, "X"), gagne(g, "O"))

Résultat : True False. X a rempli la diagonale principale, dont les cases ont leurs deux indices égaux (grille[k][k]) ; l'autre diagonale est grille[k][2 - k].

Tu avais trouvé ?

Exercice 6 sur 6 Inventaire avec des dictionnaires Réussi À revoir

À partir de la liste parc de dictionnaires du cours, écris un programme qui affiche la valeur d'achat totale par marque, en construisant un dictionnaire {marque: total}. Ajoute d'abord à parc un quatrième poste : {"inventaire": "PC-004", "marque": "Dell", "annee": 2024, "prix": 710.0}.

Voir la réponseMasquer la réponse de l'exercice 6
python
parc = [
    {"inventaire": "PC-001", "marque": "Dell", "annee": 2021, "prix": 649.0},
    {"inventaire": "PC-002", "marque": "HP", "annee": 2023, "prix": 799.0},
    {"inventaire": "PC-003", "marque": "Lenovo", "annee": 2019, "prix": 520.0},
]
parc.append({"inventaire": "PC-004", "marque": "Dell", "annee": 2024, "prix": 710.0})

totaux = {}
for poste in parc:
    marque = poste["marque"]
    totaux[marque] = totaux.get(marque, 0) + poste["prix"]
print(totaux)
text
{'Dell': 1359.0, 'HP': 799.0, 'Lenovo': 520.0}

totaux.get(marque, 0) renvoie 0 la première fois qu'une marque apparaît : c'est la version courte du if … in … else du comptage. C'est l'équivalent Python d'un GROUP BY marque avec SUM(prix) en SQL.

Tu avais trouvé ?

Chapitre terminé !

Fais les 6 exercices avant de passer à la suite : c'est en t'entraînant que tout se fixe.

chapitres
–
de série
–
du cours
–
Chapitre suivant : Chaînes de caractères et code de CésarRevoir le sommaire du cours