Adloun

NSI (première) · Chapitre 5 · Exercice de TD

Écrire inverse(d) qui échange clés et valeurs

Les dictionnaires · Construire, lire, modifier · niveau 2

É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"]}

100 % gratuit

Essaie le suivant avec le tuteur

Faire l'exercice suivant avec le tuteur

Sans compte : le cours, 2 minutes de podcast et de vidéo et un exercice avec le tuteur. Pour tout le reste : inscription gratuite en 30 secondes, sans carte bancaire.

Le cours du chapitre · Tous les exercices du chapitre

Exercice suivant avec le tuteur →