Semaine 2 · Jour 3 · 420-SN1

STRUCTURES DE DONNÉES

espece taille age
0
1
2
0
3
0
5
1
1
4
2
Ranger les données : par étiquette, ou en grille

On connaît déjà : la liste

hauteurs = [12, 18, 9] hauteurs[0] # 12 hauteurs[1] # 18 hauteurs[2] # 9
12
indice 0
18
indice 1
9
indice 2

Pratique... mais il faut se souvenir QUE l'indice 0 = la première hauteur, l'indice 1 = la deuxième, etc. Et si on rangeait par NOM plutôt que par numéro ?

Le dictionnaire : une étiquette, une valeur

dictionnaire arbre
espece "sapin" taille 12 age 40
arbre = { "espece": "sapin", "taille": 12, "age": 40 } print(arbre["espece"]) # sapin

Au lieu d'un numéro de position, on range et on retrouve par une CLÉ - le nom du tiroir. La clé est entre guillemets, la valeur peut être de n'importe quel type.

Une entrée : l'étiquette dehors, la valeur dedans

La languette = la clé La case = la valeur
espece "sapin" taille 12 age 40

La languette qui dépasse, c'est la clé - le nom qu'on lit de l'extérieur. Ce qui est rangé dans la case, c'est la valeur. Un dictionnaire, c'est une rangée de ces cases étiquetées.

Lire une valeur : la copier dans une variable

# Le dictionnaire du sapin arbre = {"espece": "sapin", "taille": 12, "age": 40} # Copier une valeur dans une variable tailleSapin = arbre["taille"] print(tailleSapin) # 12
taille 12
↓ copie
tailleSapin = 12

L'opération la plus courante : on connaît la clé, on lit sa valeur avec arbre["taille"] et on la range souvent dans une variable pour s'en servir. C'est une simple lecture - le dictionnaire n'est pas modifié.

Ouvrir un tiroir, changer son contenu

# Modifier un tiroir existant arbre["taille"] = 13 # Ajouter un nouveau tiroir arbre["estVivant"] = True
dictionnaire arbre
espece "sapin" taille 12 → 13 age 40 estVivant True
grisé = inchangé violet = modifié pointillé = ajouté

La syntaxe est la même pour modifier (clé existante) et pour ajouter (nouvelle clé). Si la clé n'existe pas encore, Python crée un nouveau tiroir.

Faire le tour des tiroirs

# Parcourir les clés seulement for cle in arbre: print(cle, ":", arbre[cle])
# Parcourir clé ET valeur ensemble for cle, valeur in arbre.items(): print(cle, valeur)
espece : sapin
taille : 13
age : 40
estVivant : True
sortie console

.items() donne chaque paire (clé, valeur) d'un coup. Mais parcourir toutes les clés est en fait assez rare : d'habitude on connaît la clé et on y va directement (arbre["taille"]). On parcourt surtout quand on ne connaît pas les clés d'avance - déboguer du code qui crée des clés à la volée, ou inspecter des données reçues d'une fonction qu'on n'a pas programmée.

Trois noms, une seule structure

DICTIONNAIRE

Le mot de Python

Le nom qu'on tape dans le code : dict. Des paires clé → valeur entre accolades.

en anglais : dictionary (dict)
{"couleur": "coeur"}

TABLEAU ASSOCIATIF

Le nom général

Le concept, hors de tout langage : on associe une clé à une valeur. JavaScript, PHP, Java... ont le même outil.

en anglais : associative array
clé ↦ valeur

TABLE DE HACHAGE

sous le capot

La mécanique interne : une fonction de hachage range chaque clé à sa place pour la retrouver presque instantanément.

en anglais : hash table, hashmap, hashtable
hash("coeur") → case

Même structure, trois points de vue : le mot Python, l'idée générale et la machinerie. Retrouver une valeur par sa clé reste presque aussi rapide, que le dictionnaire contienne 10 ou 10 000 entrées.

À quoi sert un tableau associatif ?

🎨 Simplifier
Un nom court → une valeur exacte (ROUGE → le code couleur).
🌍 Traduire
Une clé de texte → la phrase dans chaque langue.
🔁 Correspondre
Aller et revenir entre deux mondes (symbole ↔ nom).
📇 Décrire un objet
Les mêmes champs partout = les colonnes d'un CSV.
📝 Un formulaire
Chaque champ (clé) → la réponse saisie (valeur).
🔢 Compter
Chaque élément → son nombre d'occurrences.

Le point commun : on retrouve une valeur par un nom, pas par une position. On regarde chaque cas avec un tableau d'exemples.

Usage - Simplifier : un nom, un code exact

COULEURCODE EXACT
"ROUGE""#FF0000"
"VERT""#00FF00"
"BLEU""#0000FF"
"NOIR""#000000"
couleurs = { "ROUGE": "#FF0000", "VERT": "#00FF00", "BLEU": "#0000FF", } print(couleurs["ROUGE"]) # #FF0000

On manipule des noms simples (ROUGE) ; le dictionnaire garde le code exact. Ce code n'est écrit qu'une seule fois - un seul endroit à corriger si on change de teinte.

Usage - Traduire un site

CLÉFRANÇAISENGLISH
"accueil""Bienvenue""Welcome"
"panier""Panier""Cart"
"payer""Payer""Checkout"
"merci""Merci !""Thanks!"

Le site affiche textes[langue]["accueil"]. Changer de langue = changer de dictionnaire, sans toucher au reste du code. C'est le coeur de tout site multilingue.

Usage - Aller et revenir : la correspondance inverse

symbole → nom
SYMBOLENOM
"H""Hydrogène"
"O""Oxygène"
"Na""Sodium"
nom → symbole
NOMSYMBOLE
"Hydrogène""H"
"Oxygène""O"
"Sodium""Na"

Deux dictionnaires miroirs : l'un pour aller, l'autre pour revenir. On peut même fabriquer l'inverse automatiquement : inverse = {nom: sym for sym, nom in symboles.items()}.

Usage - Décrire un objet : les colonnes d'un CSV

ESPÈCETAILLEÂGE
"erable"1240
"pin"1865
"bouleau"921
foret = [ {"espece": "erable", "taille": 12, "age": 40}, {"espece": "pin", "taille": 18, "age": 65}, ]

Quand tous les dictionnaires partagent les mêmes clés, ces clés deviennent les colonnes. Une liste de dictionnaires = les lignes d'un fichier CSV ou d'un tableur Excel.

Usage - Un formulaire et ses réponses

CHAMPRÉPONSE
"nom""Maya Tremblay"
"courriel""maya@exemple.ca"
"age"17
"infolettre"True
reponses = { "nom": "Maya Tremblay", "age": 17, } print(reponses["nom"])

Un formulaire se lit tout naturellement comme un dictionnaire : chaque champ est une clé, chaque réponse est sa valeur. C'est exactement la forme que renvoie un formulaire web.

Usage - Compter les occurrences

ÉLÉMENTNOMBRE
"le"8
"arbre"5
"forêt"3
"vert"2
compte = {} for mot in texte: if mot not in compte: compte[mot] = 0 compte[mot] = compte[mot] + 1

La clé est l'élément, la valeur est son compteur. Si l'élément est nouveau, on part de zéro ; sinon on lui ajoute 1. Un classique pour analyser un texte, des votes ou des ventes.

Compter les lunchs : poulet ou végétarien ?

lunchs = ["poulet", "vegetarien", "poulet", "poulet", "vegetarien"] compte = {} for plat in lunchs: if plat not in compte: compte[plat] = 0 compte[plat] = compte[plat] + 1 print(compte) # {'poulet': 3, 'vegetarien': 2}
PLATNOMBRE
🍗 "poulet"3
🥗 "vegetarien"2

La même recette de comptage sur une vraie question : combien de lunchs de chaque sorte ? Chaque plat (la clé) garde son total (la valeur). Idéal pour une commande de groupe, un sondage ou un inventaire.

À quoi ça sert ? Une main de cartes

# Une carte = un dictionnaire carte = {"couleur": "coeur", "valeur": "A"} # Une main = une liste de cartes main = [ {"couleur": "coeur", "valeur": "A"}, {"couleur": "pique", "valeur": "R"}, {"couleur": "coeur", "valeur": "10"}, ] print(main[0]["valeur"]) # A
A
R
10
la main = 3 dictionnaires

Chaque carte porte ses attributs nommés (couleur, valeur) - bien plus clair que de retenir « l'indice 0 = la couleur ». Une main, c'est tout simplement une liste de dictionnaires.

Parcourir la main : une boucle sur les cartes

# Visiter chaque carte de la main for carte in main: print(carte["valeur"], "de", carte["couleur"])
A de coeur
R de pique
10 de coeur
sortie console

La boucle for visite chaque carte (chaque dictionnaire) de la liste. Pour chacune, on lit ses champs par leur nom. C'est le motif liste de dictionnaires + boucle qu'on retrouve partout : une main de cartes, un tableur, des résultats d'expérience.

Les couleurs : chaîne ou constante ?

Avec des chaînes - fragile
carte = {"couleur": "coeur"} # "Coeur" ? "coeurs" ? "COEUR" ? # une faute de frappe = un bug # silencieux
Avec des constantes - sûr
# L'ensemble fixe des couleurs COEUR = "coeur" PIQUE = "pique" CARREAU = "carreau" TREFLE = "trefle" carte = {"couleur": COEUR}

Une constante (en MAJUSCULES) nomme une valeur fixe, écrite une seule fois. Fini les fautes de frappe, l'éditeur complète pour toi. Regrouper ces couleurs liées, c'est exactement l'idée de enum.Enum en Python - mais ça commence ici : nommer l'ensemble des valeurs possibles.

Les couleurs comme clés : associer un emoji

COULEURÀ AFFICHER
"coeur"♥️
"carreau"♦️
"pique"♠️
"trefle"♣️
# La couleur donne le symbole a afficher symbole = { "coeur": "♥️", "pique": "♠️", "carreau": "♦️", "trefle": "♣️", } print(symbole["coeur"]) # ♥️

Encore un tableau associatif : la couleur (la clé, une donnée interne comme "coeur") donne le symbole à afficher (la valeur, ♥️). On transforme une donnée du programme en quelque chose de joli à l'écran - et on combine ça avec les constantes ou l'enum d'à côté.

Les enums : nommer l'ensemble des valeurs

from enum import Enum class Couleur(Enum): COEUR = "coeur" PIQUE = "pique" CARREAU = "carreau" TREFLE = "trefle" carte = {"couleur": Couleur.COEUR} print(Couleur.COEUR.value) # coeur
  • Un type qui regroupe des valeurs nommées liées
  • Impossible d'inventer une couleur qui n'existe pas
  • On peut les parcourir : for couleur in Couleur:

Un Enum rassemble sous un seul nom (Couleur) toutes les valeurs possibles. On écrit Couleur.COEUR : lisible, vérifié par Python, et la valeur réelle reste accessible avec .value.

Constantes ou enum : lequel choisir ?

AspectCONSTANTES (MAJ)enum.Enum
RegroupéesNon, éparpilléesOui, un seul type
Valeur invalidePossibleBloquée par le type
Parcourir toutÀ la mainfor couleur in Couleur
SyntaxeTrès simpleUn peu plus longue

Les deux valent mieux que des chaînes nues. Constantes : simples, parfaites pour débuter ou pour quelques valeurs. Enum : plus sûr et structuré quand l'ensemble des valeurs compte vraiment (couleurs, états, jours de la semaine...).

Au Projet 3

PARTIE 2
LE TABLEAU 2D

La grille à lignes et colonnes. Pas aux examens - mais elle te servira au Projet 3 (cartes, images, plateau de jeu).

Le tableau 2D : lignes et colonnes

col 0
col 1
col 2
lig 0
3
0
5
lig 1
1
4
2
foret[1][2] = 2
foret = [ [3, 0, 5], [1, 4, 2], ] # ligne 1, colonne 2 print(foret[1][2]) # 2

Un tableau 2D = une liste de listes. foret[ligne][colonne] donne la cellule exacte. Parfait pour modéliser une carte, une grille de parcelles, une image pixel par pixel.

Visiter toute la grille

for ligne in foret: for valeur in ligne: print(valeur, end=" ") print() # saut de ligne
3 0 5
1 4 2
sortie console
  • La boucle extérieure parcourt les lignes
  • La boucle intérieure parcourt les valeurs d'une ligne
  • Noms sémantiques : ligne et valeur, jamais i ou j

Visiter la grille pour calculer

foret = [[3, 0, 5], [1, 4, 2]] total = 0 for ligne in foret: for valeur in ligne: total = total + valeur print(total) # 15
3
0
5
1
4
2
total = 15

Visiter ne sert pas qu'à afficher : on peut accumuler un total, compter des cases, chercher un maximum... La double boucle voit chaque cellule une fois, et on additionne au passage.

Tic-tac-toe : écrire et lire une case

# Une grille 3x3 vide grille = [ [" ", " ", " "], [" ", " ", " "], [" ", " ", " "], ] # Écrire un O au centre grille[1][1] = "O" # Lire cette case print(grille[1][1]) # O
0
1
2
0
1
O
2
grille[1][1] = "O"

Un plateau de tic-tac-toe, c'est un tableau 2D. grille[ligne][colonne] = "O" écrit dans une case ; grille[ligne][colonne] la relit. Lignes et colonnes sont numérotées à partir de 0 - le centre, c'est [1][1].

Au Projet 3

PARTIE 3
NUMPY

Les tableaux faits pour le calcul scientifique : appliquer une opération à des milliers de nombres d'un seul coup, et sortir des statistiques en une ligne.

NumPy : calculer sur tout le tableau d'un coup

Liste Python - une boucle
hauteurs = [12, 18, 9] doubles = [] for hauteur in hauteurs: doubles.append(hauteur * 2) # [24, 36, 18]
NumPy - une ligne
import numpy as np hauteurs = np.array([12, 18, 9]) doubles = hauteurs * 2 # array([24, 36, 18])

NumPy applique l'opération à chaque élément automatiquement (la vectorisation). Attention : sur une liste Python, hauteurs * 2 recopie la liste au lieu de doubler les nombres - c'est tout l'intérêt de NumPy.

Une opération sur TOUT le tableau d'un coup

mesures + 10
10
20
30
40
↓ +10 partout
20
30
40
50
mesures / 10
10
20
30
40
↓ /10 partout
1.0
2.0
3.0
4.0

Une seule opération - + 10, / 10, * 2... - s'applique à chaque case en même temps, sans aucune boucle. Idéal pour mettre des mesures à l'échelle, convertir des unités (°F → °C) ou normaliser des données.

Des statistiques en une ligne

MÉTHODERÉSULTAT
mesures.mean()13.25
mesures.max()18.0
mesures.min()9.0
mesures.sum()53.0
mesures.std()3.27
import numpy as np mesures = np.array([12.0, 18.0, 9.0, 14.0]) print(mesures.mean()) # 13.25

Moyenne, écart-type, somme, min, max... NumPy offre directement les outils d'analyse de données - exactement ce qu'il faut pour traiter des mesures dans le Projet 2 et le Projet 3.

Tableaux 2D avec NumPy : la matrice

foret = np.array([[3, 0, 5], [1, 4, 2]]) foret.shape # (2, 3) -> 2 lignes, 3 colonnes foret[1, 2] # 2 -> ligne 1, colonne 2 foret.sum() # 15
  • Liste de listes : foret[1][2]
  • NumPy : foret[1, 2] (une seule paire de crochets)
  • On calcule sur toute la matrice d'un coup

Même idée que le tableau 2D, mais NumPy l'écrit foret[ligne, colonne] et connaît sa forme avec .shape. Parfait pour les images, les grilles et les matrices scientifiques.

Les types de NumPy : pas des int et float ordinaires

import numpy as np mesures = np.array([12, 18, 9]) type(mesures) # numpy.ndarray type(mesures[0]) # numpy.int64 type(mesures.mean()) # numpy.float64
EN PYTHONEN NUMPY
listnumpy.ndarray
intnumpy.int64
floatnumpy.float64

NumPy a ses propres types, conçus pour le calcul rapide. Ils s'utilisent comme des nombres normaux (addition, comparaison...), mais ce ne sont pas les int / float de Python, et un tableau n'est pas une list. Si un code hors NumPy exige un vrai entier ou flottant Python, on convertit : int(valeur) ou float(valeur).

La grande question

PARTIE 4
CHOISIR UNE STRUCTURE

Liste, dictionnaire, tableau 2D ou NumPy ? La vraie compétence n'est pas de connaître la syntaxe, mais de reconnaître quelle structure répond à quelle question.

Liste, dictionnaire, grille ou NumPy ?

LISTE

Ordre et position

Une suite de mesures, des températures heure par heure, des résultats de mesure.

On accède par indice numérique.

[12, 18, 9, 14]

DICTIONNAIRE

Étiquette et valeur

Les attributs d'un arbre, les caractéristiques d'une espèce, une fiche d'observation.

On accède par clé nommée.

{"espece": "erable"}

TABLEAU 2D

Grille et coordonnées

Une carte de forêt, une image, un relevé de terrain en lignes et colonnes.

On accède par [ligne][colonne].

[[3,0],[1,4]]

NUMPY

Calcul sur des nombres

Des milliers de mesures, des matrices, des images à traiter d'un seul coup.

On calcule vectorisé ; accès en [ligne, colonne].

np.array([12, 18, 9])

La clé : quel type de question pose-t-on ? "Quel est le 3e ?" (liste), "Quel est l'âge ?" (dict), "La cellule ligne 1, colonne 2 ?" (tableau 2D), "La moyenne de 10 000 mesures ?" (NumPy).

À TOI DE JOUER

Tape un dictionnaire ou une grille et regarde la mémoire se construire pas à pas :

pythontutor.com/visualize.html

Essaie : colle ton dictionnaire arbre ou ton tableau 2D foret et clique sur "Visualize Execution".

AU TRAVAIL !

espece "bouleau" taille 21 age 55
Séance 2-3 : modélise un arbre en dictionnaire, dessine ta forêt en tableau 2D
⤺ Refermer le diaporama