web-dev-qa-db-fra.com

En Python, comment puis-je parcourir un dictionnaire dans un ordre de clé trié?

Il existe une fonction existante qui se termine par ce qui suit, où d est un dictionnaire:

return d.iteritems()

qui retourne un itérateur non trié pour un dictionnaire donné. Je voudrais retourner un itérateur qui passe en revue les éléments triés par clé. Comment je fais ça?

201
mike

Je n'ai pas testé cela de manière approfondie, mais cela fonctionne dans Python 2.5.2.

>>> d = {"x":2, "h":15, "a":2222}
>>> it = iter(sorted(d.iteritems()))
>>> it.next()
('a', 2222)
>>> it.next()
('h', 15)
>>> it.next()
('x', 2)
>>>

Si vous avez l'habitude de faire for key, value in d.iteritems(): ... au lieu d'itérateurs, cela fonctionnera toujours avec la solution ci-dessus.

>>> d = {"x":2, "h":15, "a":2222}
>>> for key, value in sorted(d.iteritems()):
>>>     print(key, value)
('a', 2222)
('h', 15)
('x', 2)
>>>

Avec Python 3.x, utilisez d.items() au lieu de d.iteritems() pour renvoyer un itérateur.

165
Chris Cameron

Utilisez la fonction sorted() :

return sorted(dict.iteritems())

Si vous voulez un itérateur réel sur les résultats triés, puisque sorted() renvoie une liste, utilisez:

return iter(sorted(dict.iteritems()))
80
Greg Hewgill

Les clés d'un dict sont stockées dans une table de hachage, c'est donc leur "ordre naturel", c'est-à-dire psuedo-random. Toute autre commande est un concept de consommateur de dict.

trié () retourne toujours une liste, pas un dict. Si vous lui passez un dict.items () (qui produit une liste de tuples), il retournera une liste de tuples [(k1, v1), (k2, v2), ...] qui peuvent être utilisés en boucle d'une manière très semblable à un dict, mais ce n'est en aucun cas un dict!

foo = {
    'a':    1,
    'b':    2,
    'c':    3,
    }

print foo
>>> {'a': 1, 'c': 3, 'b': 2}

print foo.items()
>>> [('a', 1), ('c', 3), ('b', 2)]

print sorted(foo.items())
>>> [('a', 1), ('b', 2), ('c', 3)]

Ce qui suit ressemble à un dict dans une boucle, mais ce n’est pas le cas, c’est une liste de n-uplets décompactés dans k, v:

for k,v in sorted(foo.items()):
    print k, v

À peu près équivalent à:

for k in sorted(foo.keys()):
    print k, foo[k]
39
Peter Rowell

La réponse de Greg est juste. Notez que dans Python 3.0, vous devrez faire

sorted(dict.items())

comme iteritems sera parti.

30
Claudiu

Vous pouvez maintenant utiliser OrderedDict dans Python 2.7:

>>> from collections import OrderedDict
>>> d = OrderedDict([('first', 1),
...                  ('second', 2),
...                  ('third', 3)])
>>> d.items()
[('first', 1), ('second', 2), ('third', 3)]

Ici vous avez la page quoi de neuf pour la version 2.7 et la API OrderedDict .

6
Caumons

En général, on peut trier un dict comme suit:

for k in sorted(d):
    print k, d[k]

Pour le cas spécifique dans la question, ayant une "substitution au remplacement" pour d.iteritems (), ajoutez une fonction du type:

def sortdict(d, **opts):
    # **opts so any currently supported sorted() options can be passed
    for k in sorted(d, **opts):
        yield k, d[k]

et donc la ligne de fin change de

return dict.iteritems()

à

return sortdict(dict)

ou

return sortdict(dict, reverse = True)
5
pythonlarry
>>> import heapq
>>> d = {"c": 2, "b": 9, "a": 4, "d": 8}
>>> def iter_sorted(d):
        keys = list(d)
        heapq.heapify(keys) # Transforms to heap in O(N) time
        while keys:
            k = heapq.heappop(keys) # takes O(log n) time
            yield (k, d[k])


>>> i = iter_sorted(d)
>>> for x in i:
        print x


('a', 4)
('b', 9)
('c', 2)
('d', 8)

Cette méthode a toujours un tri O (N log N). Toutefois, après un bref saut heapify, les éléments sont triés dans l’ordre, ce qui le rend théoriquement plus efficace lorsque vous n’avez pas toujours besoin de la liste complète.

4
jamylak

trier renvoie une liste, d'où votre erreur lorsque vous essayez de la parcourir, mais comme vous ne pouvez pas commander un dict, vous devrez gérer une liste.

Je n'ai aucune idée du contexte plus large de votre code, mais vous pouvez essayer d'ajouter un itérateur à la liste résultante. comme ça peut-être ?:

return iter(sorted(dict.iteritems()))

bien sûr, vous allez récupérer les nuplets maintenant parce que votre dictée a été transformée en une liste de nuplets

ex: dites que votre dict était: {'a':1,'c':3,'b':2} trié le transforme en une liste:

[('a',1),('b',2),('c',3)]

ainsi, lorsque vous parcourez la liste, vous récupérez (dans cet exemple) un tuple composé d'une chaîne et d'un entier, mais vous pourrez au moins le parcourir.

3
pcn

Si vous souhaitez trier en fonction de l'ordre dans lequel les éléments ont été insérés au lieu de l'ordre des clés, jetez un coup d'œil à collections.OrderedDict de Python. (Python 3 uniquement)

3
gecco

En supposant que vous utilisez CPython 2.x et que vous ayez un dictionnaire volumineux mydict, l'utilisation de sorted (mydict) va être lente car trié génère une liste triée des clés de mydict.

Dans ce cas, vous pouvez consulter mon paquet ordereddict, qui inclut une implémentation C de sorteddict en C. Surtout si vous devez parcourir la liste triée de clés plusieurs fois à différentes étapes (nombre d'éléments) de la vie des dictionnaires.

http://anthon.home.xs4all.nl/Python/ordereddict/

2
Anthon