Écrire inverse(d) qui échange clés et valeurs
Exercice de TD · niveau 2 · NSI (première), chapitre 5 — Les dictionnaires · Construire, lire, modifier
Énoncé
Écrire inverse(d) qui échange clés et valeurs. Tester avec {"a": 1, "b": 2}, puis avec {"a": 1, "b": 1}. Que se passe-t-il ? Le dire dans la docstring plutôt que de le laisser au lecteur — puis écrire inverse_complet qui ne perd rien.
Corrigé
def inverse(d):
"""Echange cles et valeurs de d.
Precondition : les valeurs de d peuvent servir de cles (non modifiables).
Postcondition : si deux cles de d ont la MEME valeur, une seule survit --
la derniere rencontree. Le resultat a donc au plus
len(d) entrees, et strictement moins en cas de doublon.
"""
resultat = {}
for cle, valeur in d.items():
resultat[valeur] = cle
return resultat
L'inversion perd de l'information, et c'est structurel. Les clés sont uniques, les valeurs non : c'est la toute première remarque du chapitre. En inversant, les anciennes valeurs deviennent des clés — et le dictionnaire, qui n'accepte pas deux fois la même clé, en garde une seule. Sur {"a": 1, "b": 1}, le résultat est {1: "b"} : "a" a disparu, sans erreur ni avertissement. Le dictionnaire des âges du cours, où Nour et Yanis ont tous deux 17 ans, perd donc un élève.
La précondition n'est pas décorative. Les valeurs deviennent des clés : elles doivent donc être non modifiables. inverse({"x": [1, 2]}) lève TypeError: unhashable type: 'list' — l'inversion échoue sur un dictionnaire parfaitement valide, uniquement à cause de ses valeurs.
def inverse_complet(d):
"""Echange cles et valeurs SANS rien perdre : chaque valeur donne la
liste des cles qui lui etaient associees.
Postcondition : la somme des longueurs des listes du resultat vaut len(d).
"""
resultat = {}
for cle, valeur in d.items():
if valeur in resultat:
resultat[valeur].append(cle)
else:
resultat[valeur] = [cle]
assert sum(len(v) for v in resultat.values()) == len(d)
return resultat
La postcondition qui interdit la perte. sum(len(v) ...) == len(d) est exactement l'énoncé « rien n'a été perdu ». C'est la même postcondition que occurrences dans le cours, et elle joue le même rôle : elle rend l'oubli impossible à ignorer. Notez qu'aucune postcondition de ce genre ne peut être écrite pour inverse — c'est le signe qu'elle perd quelque chose.
Vérification.
assert inverse({"a": 1, "b": 2}) == {1: "a", 2: "b"}
assert inverse({"a": 1, "b": 1}) == {1: "b"} # "a" a DISPARU
assert len(inverse({"a": 1, "b": 1})) == 1
ages = {"Nour": 17, "Camille": 16, "Yanis": 17}
assert inverse(ages) == {17: "Yanis", 16: "Camille"}
assert inverse_complet(ages) == {17: ["Nour", "Yanis"], 16: ["Camille"]}Les autres exercices de ce chapitre Le cours du chapitre
Un blocage sur cet exercice ? Le tuteur d'Adloun guide par questions, sans donner la réponse.