Fusion et indexation
Introduction
Les opérations vues jusqu'ici travaillaient sur une seule table. Mais dans la vraie vie, l'information est souvent répartie sur plusieurs tables — une table des élèves, une table des notes, une table des classes — qu'il faut croiser pour répondre à une question. C'est l'opération de fusion, ou jointure.
L'opération réciproque est l'indexation : transformer une table (liste de lignes) en un dictionnaire dont les clés sont les valeurs d'une colonne. Au lieu de parcourir toute la table pour retrouver une ligne, on y accède directement.
Ce cours couvre les deux items du programme (fusion) et (indexation par clé).
Indexer une table par une colonne
Le problème
Reprenez la table des élèves :
eleves = [
{"nom": "Alice", "age": 16, "classe": "1G2"},
{"nom": "Bob", "age": 17, "classe": "1G3"},
{"nom": "Chloé", "age": 16, "classe": "1G2"},
{"nom": "Dimitri", "age": 17, "classe": "1G2"},
]
Pour retrouver Chloé, vous savez faire : parcours linéaire avec un break
(cours 2). Mais si vous voulez chercher mille fois dans une table de
dix mille élèves, vous ferez dix millions de comparaisons. Coûteux.
La solution : un dictionnaire {clé → ligne}
Un index est un dictionnaire qui associe la valeur d'une colonne unique à la ligne complète. Une fois construit, l'accès est en — quasi-instantané, quelle que soit la taille de la table.
Sortie :
{'nom': 'Chloé', 'age': 16, 'classe': '1G2'}
1G2
Version concise (compréhension de dictionnaire)
Comme pour les listes, Python propose une syntaxe compacte :
index_par_nom = {e["nom"]: e for e in eleves}
print(index_par_nom["Alice"]["age"]) # 16
Quel est l'avantage principal d'un index par clé ?
Index vs table : que choisir ?
| Structure | Accès | Coût |
|---|---|---|
| Liste de lignes | par index numérique ou parcours | pour chercher |
Index dict | par clé | pour chercher |
L'index ne remplace pas la table — il la complète. On garde la liste pour itérer dans l'ordre, on construit un index quand on a besoin de recherches répétées par clé.
Fusionner deux tables par clé commune
Le problème
Vous avez deux tables. La première liste les élèves :
eleves = [
{"nom": "Alice", "classe": "1G2"},
{"nom": "Bob", "classe": "1G3"},
{"nom": "Chloé", "classe": "1G2"},
{"nom": "Dimitri", "classe": "1G2"},
]
La seconde liste les notes obtenues à un devoir :
notes = [
{"nom": "Alice", "note": 14},
{"nom": "Bob", "note": 11},
{"nom": "Chloé", "note": 17},
{"nom": "Dimitri", "note": 9},
]
Question : produire une nouvelle table qui réunit nom, classe et note — une ligne par élève. C'est une fusion par clé commune (ici, le nom).
Solution naïve : double boucle
L'approche la plus directe est de comparer chaque ligne de la première table à chaque ligne de la seconde :
fusion = []
for e in eleves:
for n in notes:
if e["nom"] == n["nom"]:
# On crée une ligne combinée
ligne = {"nom": e["nom"], "classe": e["classe"], "note": n["note"]}
fusion.append(ligne)
for ligne in fusion:
print(ligne)
Sortie :
{'nom': 'Alice', 'classe': '1G2', 'note': 14}
{'nom': 'Bob', 'classe': '1G3', 'note': 11}
{'nom': 'Chloé', 'classe': '1G2', 'note': 17}
{'nom': 'Dimitri', 'classe': '1G2', 'note': 9}
Solution efficace : indexer puis fusionner
L'idée : indexer la seconde table par la clé commune, puis parcourir la première en consultant l'index. La complexité tombe à .
Sortie :
{'nom': 'Alice', 'classe': '1G2', 'note': 14}
{'nom': 'Bob', 'classe': '1G3', 'note': 11}
{'nom': 'Chloé', 'classe': '1G2', 'note': 17}
{'nom': 'Dimitri', 'classe': '1G2', 'note': 9}
"Chloe" vs "Chloé") casserait la jointure.Gérer les lignes orphelines
Que faire si un élève n'a pas de note (absent au devoir) ? Le test
if e["nom"] in index_notes filtre les non-correspondances. Vous pouvez
choisir :
- Jointure interne : ignorer les orphelins (ce qu'on fait au-dessus).
- Jointure externe gauche : conserver tous les élèves, marquer la note
comme
Nonequand elle manque.
fusion_externe = []
for e in eleves:
ligne = {
"nom": e["nom"],
"classe": e["classe"],
"note": index_notes.get(e["nom"]), # None si absent
}
fusion_externe.append(ligne)
La méthode dict.get(cle) renvoie None si la clé n'existe pas, au lieu
de lever KeyError.
Pourquoi indexer la 2e table avant la fusion ?
Cas particuliers et pièges
- Clés non uniques : si deux lignes de la table indexée ont la même clé,
l'index n'en garde qu'une. Si c'est gênant, construire un index
{cle: [liste de lignes]}. - Types de clé : la clé de l'index doit être hashable — les chaînes, entiers, tuples le sont ; les listes et dictionnaires ne le sont pas.
- Casse et espaces :
"Alice"et"alice "sont deux clés différentes. Normaliser (.strip().lower()) avant l'indexation. - Fusion sur plusieurs colonnes : utiliser un tuple comme clé.
index = {(e["nom"], e["classe"]): e for e in eleves}.
Pour aller plus loin
Vous reverrez ces opérations dans le chapitre Bases de données
( est l'ancêtre direct de la jointure SQL que vous
étudierez en Terminale). En attendant, vous avez tous les outils pour faire
de l'analyse de données en Python vanilla sans pandas — lecture CSV,
filtrage, tri, fusion, indexation.