cours1 min de lecture
Combiner deux tables par clé commune, indexer une table par dictionnaire pour des accès rapides.
programme

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 O(1)\mathcal{O}(1) — quasi-instantané, quelle que soit la taille de la table.

⏵ Ctrl+↵ pour exécuter
Aucune exécution pour l'instant.

Sortie :

{'nom': 'Chloé', 'age': 16, 'classe': '1G2'}
1G2
La colonne choisie comme clé doit avoir des valeurs uniques — c'est ce qu'on appelle une clé primaire (vocabulaire que vous reverrez en Terminale, , à propos du modèle relationnel). Si deux lignes ont la même valeur, la seconde écrase la première dans l'index.

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 ?

StructureAccèsCoût
Liste de lignespar index numérique ou parcoursO(n)\mathcal{O}(n) pour chercher
Index dictpar cléO(1)\mathcal{O}(1) 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}
Cette méthode a une complexité O(n×m)\mathcal{O}(n \times m) — si chaque table a 1 000 lignes, c'est un million de comparaisons. Acceptable pour de petites tables, vite catastrophique sinon.

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 à O(n+m)\mathcal{O}(n + m).

⏵ Ctrl+↵ pour exécuter
Aucune exécution pour l'instant.

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}
Domaine de valeurs partagé : la fusion par clé commune n'a de sens que si les deux tables emploient le même domaine pour cette colonne. Ici, les noms sont écrits identiquement dans les deux tables. Une orthographe divergente ("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 None quand 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.