Tri de dictionnaire {"clé": "dictionnaire"}

python

a marqué ce sujet comme résolu.

Bonjour à tous,

J’ai un dictionnaire en Python construit de la façon suivante :

players = {
  12: {
    'score1': 3,
    'score2': 8,
    'score3': 4,
  },
  20: {
    'score1': 4,
    'score2': 9,
    'score3': 1,
  },
  14: {
    'score1': 4,
    'score2': 9,
    'score3': 2,
  },

Je souhaite trier ce dictionnaire sur score1, puis score2 en cas d’égalité, puis score3 en cas d’égalité.

Malheureusement je ne vois pas du tout comment faire un tri sur une des propriétés… Pourriez-vous m’aider ?

Merci d’avance !

Salut,

On est d’accord qu’en sortie tu t’attends plutôt à obtenir une liste qu’un dictionnaire ?

Pour trier, le standard est d’utiliser la fonction sorted en lui passant les valeurs de ton dictionnaire. Cette fonction prend aussi un paramètre key, une fonction d’ordonnancement. Elle reçoit une valeur et doit renvoyer quelque chose d’ordonnable, dans ton cas il s’agirait d’un tuple composé des valeurs de score1, score2 et score3.

Impossible de trier un dictionnaire par definition (sauf depuis Python 3.7 qui garanti l’ordre par insertion).

Tu peux utiliser OrderedDict qui vient avec collections.

Et comme j’aime les one-liner degueulasse:

from collections import OrderedDict

players = {
  12: {
    'score1': 3,
    'score2': 8,
    'score3': 4,
  },
  20: {
    'score1': 4,
    'score2': 9,
    'score3': 1,
  },
  14: {
    'score1': 4,
    'score2': 9,
    'score3': 2,
  }
}

OrderedDict(sorted(iteritems(players), key=lambda x: sorted(iteritems(x[1]), key=lambda y: y[0])))

Decortiquons ce qu’il se passe:

  1. iteritems va renvoyer une liste (donc triable) fait de pair (cle, valeur)
  2. sorted permet de trier la liste
  3. l’argument key de la methode sorted indique avec quelle cle on veut trier. Je te rappelle que chaque element de la liste a trier est (cle, valeur). Exemple: (12, { 'score1': 3, 'score2': 8, 'score3': 4, }).
  4. On accede donc au dictionnaire qui contient les differents scores qu’il nous faut egalement trier (je suppose que tes cles doivent etre triees par ordre lexicographique). Autrement dit, sur l’exemple precendent iteritems(x[1]) va retourner [('score1', 3), ('score2', 8), ( 'score3', 4)], puis on va trier par les clefs.
  5. La fonction sorted precedente recupere donc [3,8,4].
  6. Comme la comparaison sur entre deux listes d’entiers s’opere entier par entier, cela permet d’obtenir le resultat voulu.
>>> OrderedDict(sorted(iteritems(players), key=lambda x: sorted(iteritems(x[1]), key=lambda y: y[0])))
OrderedDict([(12, {'score1': 3, 'score2': 8, 'score3': 4}), (20, {'score1': 4, 'score2': 9, 'score3': 1}), (14, {'score1': 4, 'score2': 9, 'score3': 2})])
+0 -0

Il n’existe pas de fonction iteritems en Python. Il y avait bien en Python 2 une méthode des dictionnaires portant ce nom, mais elle a disparu avec Python 3. Le plus simple est de juste utiliser players.items() si les clés sont importantes, et players.values() si seules les valeurs importent.

Merci pour votre aide à tous les deux.

On est d’accord qu’en sortie tu t’attends plutôt à obtenir une liste qu’un dictionnaire ?

En effet, de toute façon peu importe, je pourrai me débrouiller avec l’un ou l’autre vu que je peux itérer dessus.

@KFC, effectivement en testant j’ai eu le problème du fait qu’iteritems n’existait pas (je suis en python 3.6). Comment puis-je adapter ton code ?

Python 3.6.7 (default, Oct 22 2018, 11:32:17) 
[GCC 8.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from collections import OrderedDict
>>> 
>>> players = {
...   12: {
...     'score1': 3,
...     'score2': 8,
...     'score3': 4,
...   },
...   20: {
...     'score1': 4,
...     'score2': 9,
...     'score3': 1,
...   },
...   14: {
...     'score1': 4,
...     'score2': 9,
...     'score3': 2,
...   }
... }


>>> OrderedDict(sorted(players.items(), key=lambda x: sorted(x[1].keys())))
OrderedDict([(12, {'score1': 3, 'score2': 8, 'score3': 4}), (20, {'score1': 4, 'score2': 9, 'score3': 1}), (14, {'score1': 4, 'score2': 9, 'score3': 2})])

@KFC Le résultat de ton dernier exemple est bon parce que le dictionnaire en entrée est déjà trié dans le bon ordre.

Mais la fonction key que tu donnes à sorted n’a pas l’effet voulu : elle renvoie pour chaque élément un objet équivalent à ('score1', 'score2', 'score3') donc pas de différence entre les éléments et pas de tri.

Connectez-vous pour pouvoir poster un message.
Connexion

Pas encore membre ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte