web-dev-qa-db-fra.com

Comment trier les dictionnaires par clés en Python

Quelqu'un peut-il me dire comment je peux trier ceci:

{'a': [1, 2, 3], 'c': ['one', 'two'], 'b': ['blah', 'bhasdf', 'asdf'], 'd': ['asdf', 'wer', 'asdf', 'zxcv']}

dans

{'a': [1, 2, 3], 'b': ['blah', 'bhasdf', 'asdf'], 'c': ['one', 'two'],'d': ['asdf', 'wer', 'asdf', 'zxcv']}

?Merci!

UPDATE 1, exemple de code:

Donc je fais de la linguistique. Un article est décomposé en mots qui sont stockés dans une base de données et ont toutes sortes de propriétés, y compris ID para et ID phrase. La tâche: essayer de reconstruire le texte original.

Obtenez 500 mots consécutifs de la base de données

words = Words.objects.all()[wordId:wordId+500]
# I first create paragraphs, through which I can loop later in my Django template,
# and in each para will be a list of words (also dictionaries). 
# So i am trying to get a dictionary with values that are lists of dictionaries. 
# 'pp' i make just for shorthanding a long-named variable.
paras={}
para_high = para_low =  words[0].belongs_to_paragraph
for w in words:
    last_Word = w
    pp = w.belongs_to_paragraph
    if pp >para_high:
        para_high = pp
    if pp < para_low:
        para_low = pp
    if pp in paras:
        paras[pp].append(w)
    else:
        list = [w]
        paras[pp] = list
# Since there are blank lines between paragraphs, in rebuilding the text as it 
    #  looked originally, I need to insert blank lines. 
    # Since i have the ID's of the paragraphs and they go somewhat like that: 1,3,4,8,9 
    #(the gaps between 1 & 3 and 4 & 8 i have to fill in with something else, 
    # which is why i had para_low and para_high to loop the range. 
isbr = True
for i in range(para_low, para_high+1):
    if i in paras:
        isbr = True
    else:
        if isbr:
            paras[i]=['break']
            isbr = False
        else:
            paras[i]=[]

À ce stade, cependant, si j'essaie de boucler le dict et de reconstruire le texte, certains paragraphes plus tard, id'd, viennent avant les précédents, et cela ne le fait tout simplement pas.

UPDATE 2, code de la boucle:

        {% for k,v in wording.iteritems()  %}
        {% if v[0] == 'break' %}
        <br/>
        {% else %}
        </div><div class="p">{% for Word in v %}{% if Word.special==0%} {% endif %}<span class="Word {% if Word.special == 0%}clickable{% endif%}" wid="{{Word.id}}" special="{{Word.special}}" somethingElse={{Word.somethingElse}}>{{ Word.word }}</span>{% endfor %}
        {% endif %}
    {% endfor %}
18
mgPePe

Les dict n'ont pas d'ordre.

Vous pouvez appeler les appels en ordre, mais cela vous donne simplement une liste des touches:

>>> sorted(d)
['a', 'b', 'c', 'd']

Vous pouvez la traiter comme une variable et trier les nuplets valeur-clé, mais vous obtenez alors une liste de nuplets. Ce n'est pas la même chose qu'un dict.

>>> sorted(d.items())
[
 ('a', [1, 2, 3]),
 ('b', ['blah', 'bhasdf', 'asdf']),
 ('c', ['one', 'two']),
 ('d', ['asdf', 'wer', 'asdf', 'zxcv'])
]

Si vous utilisez Python 2.7 ou une version plus récente, vous pouvez également utiliser un OrderedDict .

dict sous-classe qui se souvient des commandes ont été ajoutées

Par exemple:

>>> d = collections.OrderedDict(sorted(d.items()))
>>> for k, v in d.items():
>>>     print k, v
 a [1, 2, 3] 
 b ['blah', 'bhasdf', 'asdf'] 
 c ['un', 'deux'] 
 d ['asdf', 'wer', 'asdf', 'zxcv'] 
46
Mark Byers

La réponse correcte est que si vous voulez que les éléments d’un dictionnaire soient triés, vous devez utiliser la fonction triée () _ {lorsque vous parcourez le dictionnaire}:

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

ou 

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

Ou similaire.

OrderedDict mentionné est destiné aux dictionnaires qui ont un ordre. Et l'ordre n'est pas la même chose qu'un tri. Vous pouvez créer un OrdreDict trié, oui, mais dès que vous ajoutez une nouvelle clé, celle-ci n'est plus triée. Vous auriez donc besoin de la façon triée () malgré tout pour le trier avant chaque utilisation ou après chaque manipulation. OrderedDict n’est donc que plus lent et nécessite plus de mémoire qu’un dictionnaire ordinaire, sans rien rajouter. 

OrderedDict sont pas pour les dictionnaires triés, mais pour les dictionnaires dont les éléments ont un ordre quelconque qui est pas un tri. Par exemple, si vous souhaitez afficher les éléments dans l'ordre dans lequel ils ont été ajoutés ou si vous souhaitez que les utilisateurs puissent commander les éléments de manière arbitraire. 

Mise à jour: Explication complémentaire

Pourquoi OrderedDict n'est-il pas une solution? Parce qu'un OrderedDict est ordonné pas trié

Considérons un dictionnaire standard:

>>> d = {'a': 0, 'b': 1, 'c': 2, 'd': 3, 'e': 4, 'f': 5}

Ce n'est pas trié, comme on le voit ci-dessous, "c" viendra avant "b". De plus, il n’ya pas d’ordre, si nous ajoutons de nouvelles choses, il apparaît ce qui semble être un ordre aléatoire:

>>> d['g'] = 6
>>> d['i'] = 8
>>> d
{'a': 0, 'c': 2, 'b': 1, 'e': 4, 'd': 3, 'g': 6, 'f': 5, 'i': 8}

OK, alors utilisons un OrderedDict alors:

>>> o = OrderedDict(sorted({'a': 0, 'b': 1, 'c': 2, 'd': 3, 'e': 4, 'f': 5}.items()))
>>> o
OrderedDict([('a', 0), ('b', 1), ('c', 2), ('d', 3), ('e', 4), ('f', 5)])

Aha! Trié! Donc, OrderedDict fonctionne !? Non. 

>>> o['i'] = 8
>>> o['g'] = 6
>>> o
OrderedDict([('a', 0), ('b', 1), ('c', 2), ('d', 3), ('e', 4), ('f', 5), ('i', 8), ('g', 6)])

Quoi? Le g a fini par après le i?!? Pourquoi!? Parce que OrderedDict n'est pas trié, il s'agit de ordonné. Il se souvient de la ordre vous ajoutez des choses. Pas le tri. Cela signifie que chaque fois que vous l'utilisez, vous devez d'abord le trier. OrderedDict ne restera trié que si vous n'y ajoutez pas de clés. Mais si vous n'allez pas le modifier, vous n'avez pas besoin d'un dict. Vous pouvez aussi bien avoir une liste. Quel est ce que vous obtenez de trier ():

>>> sorted(o.items())
[('a', 0), ('b', 1), ('c', 2), ('d', 3), ('e', 4), ('f', 5), ('g', 6), ('i', 8)]

Mais cela fonctionne tout aussi bien avec le dictionnaire standard, donc OrderedDictionary n'a pas aidé:

>>> sorted(d.items())
[('a', 0), ('b', 1), ('c', 2), ('d', 3), ('e', 4), ('f', 5), ('g', 6), ('i', 8)]

Conclusion Ainsi, chaque fois que vous souhaitez parcourir le dictionnaire de manière triée, vous devez effectuer les opérations suivantes:

>>> for k in sorted(o):
...   print k, o[k]
... 
a 0
b 1
c 2
d 3
e 4
f 5
g 6
i 8

Et c’est quel que soit le dictionnaire que vous utilisez. OrderedDict ne vous aide pas vraiment, car il se fiche de trier, juste du ordre vous ajoutez des éléments.

29
Lennart Regebro

Il est à noter que Python dispose de nombreuses implémentations de dictionnaire qui maintiennent les clés dans un ordre trié. Considérez le module triedcontainers qui est une implémentation pure-Python et fast-as-C. Il existe une comparaison performance avec d'autres implémentations rapides et complètes, comparées les unes aux autres.

Par exemple:

>>> from sortedcontainers import SortedDict
>>> d = {'a': [1, 2, 3], 'c': ['one', 'two'], 'b': ['blah', 'bhasdf', 'asdf'], 'd': ['asdf', 'wer', 'asdf', 'zxcv']}
>>> s = SortedDict(**d)
>>> s.keys()
SortedSet(['a', 'b', 'c', 'd'])

Vous pouvez également remplacer entièrement votre utilisation de dict par SortedDict car il prend en charge les opérations d'obtention/définition rapides et les itérations triées d'éléments par clé.

5
GrantJ

Comme mentionné dans l'autre réponse, l'ordre des clés d'un dictionnaire est arbitraire et vous ne devez pas vous en fier.

Si vous utilisez Python 2.7 ou 3.1 ou ultérieur, essayez collections.OrderedDict ( 2.7 docs ; 3.1 docs ; voir aussi PEP 372 ). La documentation contient un lien vers une version pure-Python de OrderedDict qui fonctionne sur les versions antérieures de Python.

1
Nicholas Riley

Je vais ajouter mon un cent à ce que d'autres ont déjà expliqué. J'ai eu exactement le même problème dans un cas particulier. J'avais besoin que la sortie de mon dictionnaire soit toujours la même pour l'écriture de tests unitaires stables. 

Si par hasard, c'est ce que vous essayez d'atteindre, ou une autre tâche liée à la sortie, vous n'avez rien à trier du tout, utilisez simplement le module pprint, entre autres fonctionnalités, il triera les dictionnaires par clés.

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

>>> from pprint import pprint
>>> pprint(d)
{'a': 1, 'b': 2, 'c': 3}
0
kriss

Voici une fonction simple et rapide que vous pouvez utiliser pour trier un dictionnaire par clé. 

Placez ce code dans un fichier séparé appelé sdict.py:

def sortdict(dct):
    kys = dct.keys()
    kys.sort()
    from collections import OrderedDict
    d = OrderedDict()
    for x in kys: 
        for k, v in dct.iteritems():
            if (k == x):
                d[k] = v
    return d

Maintenant, placez ce code dans un fichier séparé appelé test.py pour le tester avec un exemple de dictionnaire:

from sdict import sortdict
import json
dct = {'sizes':[32,28,42], 'dog':'schnauser', 'cat':'siamese', 'bird':'falcon'}
dctx = sortdict(dct)
print json.dumps(dctx) 

Et enfin, appelez test.py à partir de la ligne de commande:

$ python test.py
{"bird": "falcon", "cat": "siamese", "dog": "schnauser", "sizes": [32, 28, 42]}

J'utilise uniquement la ligne json.dumps pour vous montrer que c'est un dictionnaire réel, et pas seulement une représentation sous forme de chaîne. Vous pouvez également le tester avec la fonction type () d'ailleurs.

J'ai inclus une liste imbriquée de valeurs numériques dans l'exemple de dictionnaire pour montrer que la fonction peut gérer des dictionnaires plus complexes, pas seulement des dictés basés sur des chaînes à une seule couche. 

Le code est assez simple, il serait donc facile de le modifier pour trier par valeurs, si tel est votre choix - bien que trier par valeur n’aurait pas de sens si certaines valeurs sont des objets, tels que des listes, des tuples ou d’autres dict. 

Certes, cela ne fonctionne que dans python 2.7 ou ultérieur.

À votre santé,
- = Cameron

0
Cameron Landers

Il peut également être intéressant de mentionner la plus grande routine dans heapq. Ceci trie et retourne les N premiers éléments. Selon ce qui est réellement requis, cela peut être pratique si vous jouez avec le paramètre clé. Je le mentionne surtout depuis que je l'ai découvert il y a deux ou trois nuits et qu'il a fait exactement ce que je recherchais. Voir PEP 0265 et Heapq .

0
dave