Comment trier un dictionnaire par clé?

941

Quelle serait une belle façon d'aller de {2:3, 1:89, 4:5, 3:0}à {1:89, 2:3, 3:0, 4:5}?
J'ai vérifié certains articles mais ils utilisent tous l'opérateur "trié" qui retourne les tuples.

Antony
la source
39
Les dictionnaires sont intrinsèquement non triés. L'affichage du dictionnaire est une autre affaire. Quoi qu'il en soit, de quoi avez-vous vraiment besoin pour le trier?
Karl Knechtel
15
les dictionnaires ne sont pas triés. ils ne sont tout simplement pas. si vous voulez parcourir les éléments pour que vous ayez à faire quelque chose comme vous l'avez dit en utilisant trié comme "for key in sorted (d.keys ())" en supposant que d est le nom de votre dictionnaire
Ryan Haining
3
@KarlKnechtel - mon cas d'utilisation est que j'ai une application CLI qui a un menu primitif et les options de menu sont dans un dictionnaire comme clés. Je voudrais afficher les touches par ordre alphabétique pour la raison de l'utilisateur.
Randy
4
Notez que les dict sont désormais classés par ordre d'insertion (python 3.6+). Certaines réponses ci-dessous le montrent.
matiasg

Réponses:

941

Les dictionnaires Python standard ne sont pas classés. Même si vous triiez les paires (clé, valeur), vous ne seriez pas en mesure de les stocker de dictmanière à préserver l'ordre.

La façon la plus simple est d'utiliser OrderedDict, qui se souvient de l'ordre dans lequel les éléments ont été insérés:

In [1]: import collections

In [2]: d = {2:3, 1:89, 4:5, 3:0}

In [3]: od = collections.OrderedDict(sorted(d.items()))

In [4]: od
Out[4]: OrderedDict([(1, 89), (2, 3), (3, 0), (4, 5)])

Peu importe que le chemin odsoit imprimé; cela fonctionnera comme prévu:

In [11]: od[1]
Out[11]: 89

In [12]: od[3]
Out[12]: 0

In [13]: for k, v in od.iteritems(): print k, v
   ....: 
1 89
2 3
3 0
4 5

Python 3

Pour les utilisateurs de Python 3, il faut utiliser le .items()au lieu de .iteritems():

In [13]: for k, v in od.items(): print(k, v)
   ....: 
1 89
2 3
3 0
4 5
NPE
la source
1
J'ai utilisé cela et cela fonctionne, je suppose que c'est plus de code et de redondance mais fait le travail, # dict non ordonné d = {2: 3, 1:89, 4: 5, 3: 0} orderDict = {} pour la clé en trié (d.iterkeys ()): orderDict [key] = d [key]
Antony
4
@achrysochoou: si cela a fonctionné, ce doit être par pure chance. Comme on vous l'a dit, les dictionnaires ordinaires n'ont aucun concept de tri, peu importe si vous attribuez les clés triées ou de manière aléatoire.
Ricardo Cárdenes
21
Pour python 3.7+:sorted_dict = dict(sorted(unsorted_dict.items()))
aksh1618
10
python 3.7+ ne devrait pas avoir besoin de orderDict car il commande maintenant par défaut :-)
Aneuway
3
Depuis le manuel de python 3.7.4: "L'exécution de list (d) sur un dictionnaire renvoie une liste de toutes les clés utilisées dans le dictionnaire, dans l'ordre d'insertion". L'ordre d'insertion est donc quelque chose qui est préservé et sur lequel nous pouvons compter.
Mostafa Hadian
415

Les dictionnaires eux-mêmes n'ont pas d'articles commandés en tant que tels, si vous souhaitez les imprimer, etc. dans un certain ordre, voici quelques exemples:

En Python 2.4 et supérieur:

mydict = {'carl':40,
          'alan':2,
          'bob':1,
          'danny':3}

for key in sorted(mydict):
    print "%s: %s" % (key, mydict[key])

donne:

alan: 2
bob: 1
carl: 40
danny: 3

(Python inférieur à 2.4 :)

keylist = mydict.keys()
keylist.sort()
for key in keylist:
    print "%s: %s" % (key, mydict[key])

Source: http://www.saltycrane.com/blog/2007/09/how-to-sort-python-dictionary-by-keys/

James
la source
2
Vous pouvez également utiliser OrderedDict en python 2.4+ comme dans la réponse de NPE
radtek
1
et si vous utilisez des éléments (), vous pouvez le faire commefor key, value in sorted(mydict.items())"
beep_check
Les dictionnaires eux-mêmes n'ont pas d'articles commandés en tant que tels -> n'est plus vrai!
minexew
Comment ça se fait, pouvez-vous expliquer?
James
204

De la collectionsdocumentation de la bibliothèque de Python :

>>> from collections import OrderedDict

>>> # regular unsorted dictionary
>>> d = {'banana': 3, 'apple':4, 'pear': 1, 'orange': 2}

>>> # dictionary sorted by key -- OrderedDict(sorted(d.items()) also works
>>> OrderedDict(sorted(d.items(), key=lambda t: t[0]))
OrderedDict([('apple', 4), ('banana', 3), ('orange', 2), ('pear', 1)])

>>> # dictionary sorted by value
>>> OrderedDict(sorted(d.items(), key=lambda t: t[1]))
OrderedDict([('pear', 1), ('orange', 2), ('banana', 3), ('apple', 4)])

>>> # dictionary sorted by length of the key string
>>> OrderedDict(sorted(d.items(), key=lambda t: len(t[0])))
OrderedDict([('pear', 1), ('apple', 4), ('orange', 2), ('banana', 3)])
Dennis
la source
4
impressionnant! Les gars si vous voulez inverser l'ordre (croissant vers décroissant), il vous suffit d'ajouter reverse=Truepar exempleOrderedDict(sorted(d.items(), reverse=True, key=lambda t: t[0]))
benscabbia
1
Dans PyCharm, quel que soit le dictionnaire que j'utilise, je reçois toujours cet avertissement:Unexpected type(s): (List[str]) Possible types: (Mapping) (Iterable[Tuple[Any, Any]])
Euler_Salter
153

Pour CPython / PyPy 3.6 et tout Python 3.7 ou supérieur, cela se fait facilement avec:

>>> d = {2:3, 1:89, 4:5, 3:0}
>>> dict(sorted(d.items()))
{1: 89, 2: 3, 3: 0, 4: 5}
Dipu
la source
3
Une autre façon d'écrire la même chose est d'utiliser une compréhension: {key:d[key] for key in sorted(d.keys())}
flow2k
42

Il existe un certain nombre de modules Python qui fournissent des implémentations de dictionnaire qui maintiennent automatiquement les clés dans l'ordre trié. Considérez le module sortedcontainers qui est des implémentations en Python pur et rapide en C. Il existe également une comparaison des performances avec d'autres options populaires comparées les unes aux autres.

L'utilisation d'un dict ordonné est une solution inadéquate si vous devez constamment ajouter et supprimer des paires clé / valeur tout en effectuant une itération.

>>> from sortedcontainers import SortedDict
>>> d = {2:3, 1:89, 4:5, 3:0}
>>> s = SortedDict(d)
>>> s.items()
[(1, 89), (2, 3), (3, 0), (4, 5)]

Le type SortedDict prend également en charge les recherches et les suppressions d'emplacement indexées, ce qui n'est pas possible avec le type dict intégré.

>>> s.iloc[-1]
4
>>> del s.iloc[2]
>>> s.keys()
SortedSet([1, 2, 4])
GrantJ
la source
32

Simplement:

d = {2:3, 1:89, 4:5, 3:0}
sd = sorted(d.items())

for k,v in sd:
    print k, v

Production:

1 89
2 3
3 0
4 5
user3769249
la source
6
sdest une liste de tuples, pas un dictionnaire. (toujours utile cependant.)
nischi
24

Comme d'autres l'ont mentionné, les dictionnaires sont intrinsèquement non ordonnés. Cependant, si le problème affiche simplement les dictionnaires de façon ordonnée, vous pouvez remplacer la __str__méthode dans une sous-classe de dictionnaire et utiliser cette classe de dictionnaire plutôt que la fonction intégrée dict. Par exemple.

class SortedDisplayDict(dict):
   def __str__(self):
       return "{" + ", ".join("%r: %r" % (key, self[key]) for key in sorted(self)) + "}"


>>> d = SortedDisplayDict({2:3, 1:89, 4:5, 3:0})
>>> d
{1: 89, 2: 3, 3: 0, 4: 5}

Remarque, cela ne change rien à la façon dont les clés sont stockées, à l'ordre dans lequel elles reviendront lorsque vous les itérerez, etc., à la façon dont elles seront affichées avec printou sur la console python.

Brian
la source
19

Trouvé d'une autre manière:

import json
print json.dumps(d, sort_keys = True)

upd:
1. cela trie également les objets imbriqués (merci @DanielF).
2. Les dictionnaires python ne sont pas ordonnés, c'est pourquoi ils ne peuvent être imprimés ou assignés qu'à str.

tschesseket
la source
Mais cela trie également les clés des objets imbriqués, ce qui peut ne pas être souhaité.
Daniel F
Notez que cela ne trie que les dictionnaires, pas les listes, par exemple dict.keys () ne sera pas trié car il s'agit d'une liste.
Andrew
16

En Python 3.

>>> D1 = {2:3, 1:89, 4:5, 3:0}
>>> for key in sorted(D1):
    print (key, D1[key])

donne

1 89
2 3
3 0
4 5
Evgeny Tryastsin
la source
13

Le dictionnaire Python n'était pas ordonné avant Python 3.6. Dans l'implémentation CPython de Python 3.6, le dictionnaire conserve l'ordre d'insertion. À partir de Python 3.7, cela deviendra une fonctionnalité de langage.

Dans le journal des modifications de Python 3.6 ( https://docs.python.org/3.6/whatsnew/3.6.html#whatsnew36-compactdict ):

L'aspect préservant l'ordre de cette nouvelle implémentation est considéré comme un détail d'implémentation et ne doit pas être invoqué (cela peut changer à l'avenir, mais il est souhaitable d'avoir cette nouvelle implémentation dict dans la langue pour quelques versions avant de changer la spécification de langue pour rendre obligatoire la sémantique préservant l'ordre pour toutes les implémentations Python actuelles et futures; cela permet également de préserver la compatibilité descendante avec les anciennes versions du langage où l'ordre d'itération aléatoire est toujours en vigueur, par exemple Python 3.5).

Dans le document de Python 3.7 ( https://docs.python.org/3.7/tutorial/datastructures.html#dictionaries ):

L'exécution de list (d) sur un dictionnaire renvoie une liste de toutes les clés utilisées dans le dictionnaire, dans l'ordre d'insertion (si vous voulez le trier, utilisez simplement sorted (d) à la place).

Contrairement aux versions précédentes, vous pouvez trier un dict après Python 3.6 / 3.7. Si vous souhaitez trier un dict imbriqué comprenant le sous-dict à l'intérieur, vous pouvez faire:

test_dict = {'a': 1, 'c': 3, 'b': {'b2': 2, 'b1': 1}}

def dict_reorder(item):
    return {k: sort_dict(v) if isinstance(v, dict) else v for k, v in sorted(item.items())}

reordered_dict = dict_reorder(test_dict)

https://gist.github.com/ligyxy/f60f0374defc383aa098d44cfbd318eb

Guangyang Li
la source
11

Ici, j'ai trouvé une solution la plus simple pour trier le dict python par clé en utilisant pprint. par exemple.

>>> x = {'a': 10, 'cd': 20, 'b': 30, 'az': 99} 
>>> print x
{'a': 10, 'b': 30, 'az': 99, 'cd': 20}

mais en utilisant pprint, il renverra dict dicté

>>> import pprint 
>>> pprint.pprint(x)
{'a': 10, 'az': 99, 'b': 30, 'cd': 20}
Atul Arvind
la source
10

Il existe un moyen simple de trier un dictionnaire.

Selon votre question,

La solution est:

c={2:3, 1:89, 4:5, 3:0}
y=sorted(c.items())
print y

(Où c est le nom de votre dictionnaire.)

Ce programme donne la sortie suivante:

[(1, 89), (2, 3), (3, 0), (4, 5)]

comme tu voulais.

Un autre exemple est:

d={"John":36,"Lucy":24,"Albert":32,"Peter":18,"Bill":41}
x=sorted(d.keys())
print x

Donne la sortie:['Albert', 'Bill', 'John', 'Lucy', 'Peter']

y=sorted(d.values())
print y

Donne la sortie:[18, 24, 32, 36, 41]

z=sorted(d.items())
print z

Donne la sortie:

[('Albert', 32), ('Bill', 41), ('John', 36), ('Lucy', 24), ('Peter', 18)]

Par conséquent, en le changeant en clés, valeurs et éléments, vous pouvez imprimer comme vous le vouliez.

Sree
la source
8

Générera exactement ce que vous voulez:

 D1 = {2:3, 1:89, 4:5, 3:0}

 sort_dic = {}

 for i in sorted(D1):
     sort_dic.update({i:D1[i]})
 print sort_dic


{1: 89, 2: 3, 3: 0, 4: 5}

Mais ce n'est pas la bonne façon de procéder, car cela pourrait montrer un comportement distinct avec différents dictionnaires, ce que j'ai appris récemment. Par conséquent, la voie parfaite a été suggérée par Tim dans la réponse de ma requête que je partage ici.

from collections import OrderedDict
sorted_dict = OrderedDict(sorted(D1.items(), key=lambda t: t[0]))
jax
la source
Que signifie «montrer un comportement distinct avec différents dictionnaires»? Quel est le "comportement distinct" que le tri ne peut pas gérer?
ingyhere
6

Je pense que la chose la plus simple est de trier le dict par clé et d'enregistrer la paire clé: valeur dans un nouveau dict.

dict1 = {'renault': 3, 'ford':4, 'volvo': 1, 'toyota': 2} 
dict2 = {}                  # create an empty dict to store the sorted values
for key in sorted(dict1.keys()):
    if not key in dict2:    # Depending on the goal, this line may not be neccessary
        dict2[key] = dict1[key]

Pour plus de clarté:

dict1 = {'renault': 3, 'ford':4, 'volvo': 1, 'toyota': 2} 
dict2 = {}                  # create an empty dict to store the sorted     values
for key in sorted(dict1.keys()):
    if not key in dict2:    # Depending on the goal, this line may not be  neccessary
        value = dict1[key]
        dict2[key] = value
lallolu
la source
6

Vous pouvez créer un nouveau dictionnaire en triant le dictionnaire actuel par clé selon votre question.

Ceci est votre dictionnaire

d = {2:3, 1:89, 4:5, 3:0}

Créez un nouveau dictionnaire d1 en triant ce d à l'aide de la fonction lambda

d1 = dict(sorted(d.items(), key = lambda x:x[0]))

d1 doit être {1: 89, 2: 3, 3: 0, 4: 5}, trié en fonction des clés de d.

Amit Prafulla
la source
5

Les dictés Python ne sont pas ordonnés. Habituellement, ce n'est pas un problème car le cas d'utilisation le plus courant consiste à effectuer une recherche.

La façon la plus simple de faire ce que vous voulez serait de créer une collections.OrderedDictinsertion des éléments dans l'ordre trié.

ordered_dict = collections.OrderedDict([(k, d[k]) for k in sorted(d.keys())])

Si vous avez besoin d'itérer, comme d'autres l'ont suggéré ci-dessus, le moyen le plus simple serait d'itérer sur des clés triées. Exemples-

Imprimer les valeurs triées par clés:

# create the dict
d = {k1:v1, k2:v2,...}
# iterate by keys in sorted order
for k in sorted(d.keys()):
    value = d[k]
    # do something with k, value like print
    print k, value

Obtenez la liste des valeurs triées par clés:

values = [d[k] for k in sorted(d.keys())]
Ramashish Baranwal
la source
2
for k,value in sorted(d.items()):c'est mieux: évite d'accéder à nouveau au dict par clé dans la boucle
Jean-François Fabre
4

Je propose un tri de dict sur une seule ligne.

>> a = {2:3, 1:89, 4:5, 3:0}
>> c = {i:a[i] for i in sorted(a.keys())}
>> print(c)
{1: 89, 2: 3, 3: 0, 4: 5}
[Finished in 0.4s]

J'espère que cela vous sera utile.

Jeevan Chaitanya
la source
4

Cette fonction triera récursivement tout dictionnaire par sa clé. Autrement dit, si une valeur du dictionnaire est également un dictionnaire, elle sera également triée par sa clé. Si vous utilisez CPython 3.6 ou supérieur, une simple modification pour utiliser un dictplutôt qu'un OrderedDictpeut être effectuée.

from collections import OrderedDict

def sort_dict(d):
    items = [[k, v] for k, v in sorted(d.items(), key=lambda x: x[0])]
    for item in items:
        if isinstance(item[1], dict):
            item[1] = sort_dict(item[1])
    return OrderedDict(items)
    #return dict(items)
Booboo
la source
2

Les gars, vous compliquez les choses ... c'est vraiment simple

from pprint import pprint
Dict={'B':1,'A':2,'C':3}
pprint(Dict)

La sortie est:

{'A':2,'B':1,'C':3}
Derick Fdo
la source
Voté parce que je ne connaissais pas les dictionnaires de tri de pprint pour les afficher, mais l'OP a vraiment demandé de "passer" du dict non trié au dict trié, c'est-à-dire que l'OP semble vouloir quelque chose qui reste trié en mémoire, peut-être pour un algorithme qui nécessite des clés triées
Captain Lepton
Cette méthode n'autorisera pas l'affectation chaînée car pprint n'en renvoie aucune. >>> adict = {'B': 1, 'A': 2, 'C': 3} >>> ppdict = pprint (adict) {'A': 2, 'B': 1, 'C': 3} >>> ppdict.type () Traceback (dernier appel le plus récent): Fichier "<stdin>", ligne 1, dans <module> AttributeError: l'objet 'NoneType' n'a pas d'attribut 'type'
2

La solution la plus simple consiste à obtenir une liste des clés de dict dans l'ordre trié, puis à répéter sur dict. Par exemple

a1 = {'a':1, 'b':13, 'd':4, 'c':2, 'e':30}
a1_sorted_keys = sorted(a1, key=a1.get, reverse=True)
for r in a1_sorted_keys:
    print r, a1[r]

Voici la sortie (ordre décroissant)

e 30
b 13
d 4
c 2
a 1
Shafiq
la source
2

Un moyen simple de le faire:

d = {2:3, 1:89, 4:5, 3:0}

s = {k : d[k] for k in sorted(d)}

s
Out[1]: {1: 89, 2: 3, 3: 0, 4: 5} 
pr94
la source
1

Une comparaison temporelle des deux méthodes en 2.7 montre qu'elles sont pratiquement identiques:

>>> setup_string = "a = sorted(dict({2:3, 1:89, 4:5, 3:0}).items())"
>>> timeit.timeit(stmt="[(k, val) for k, val in a]", setup=setup_string, number=10000)
0.003599141953657181

>>> setup_string = "from collections import OrderedDict\n"
>>> setup_string += "a = OrderedDict({1:89, 2:3, 3:0, 4:5})\n"
>>> setup_string += "b = a.items()"
>>> timeit.timeit(stmt="[(k, val) for k, val in b]", setup=setup_string, number=10000)
0.003581275490432745 
Jesuisme
la source
1
from operator import itemgetter
# if you would like to play with multiple dictionaries then here you go:
# Three dictionaries that are composed of first name and last name.
user = [
    {'fname': 'Mo', 'lname': 'Mahjoub'},
    {'fname': 'Abdo', 'lname': 'Al-hebashi'},
    {'fname': 'Ali', 'lname': 'Muhammad'}
]
#  This loop will sort by the first and the last names.
# notice that in a dictionary order doesn't matter. So it could put the first name first or the last name first. 
for k in sorted (user, key=itemgetter ('fname', 'lname')):
    print (k)

# This one will sort by the first name only.
for x in sorted (user, key=itemgetter ('fname')):
    print (x)
Mohammad Mahjoub
la source
1
dictionary = {1:[2],2:[],5:[4,5],4:[5],3:[1]}

temp=sorted(dictionary)
sorted_dict = dict([(k,dictionary[k]) for i,k in enumerate(temp)])

sorted_dict:
         {1: [2], 2: [], 3: [1], 4: [5], 5: [4, 5]}
Mahdi Ghelichi
la source
0

Ma suggestion est la suivante car elle vous permet de trier un dict ou de garder un dict trié pendant que vous ajoutez des éléments et devrez peut-être ajouter des éléments à l'avenir:

Construisez un à dictpartir de zéro au fur et à mesure. Ayez une deuxième structure de données, une liste, avec votre liste de clés. Le paquetage bisect a une fonction d'insort qui permet d'insérer dans une liste triée, ou de trier votre liste après avoir complètement rempli votre dict. Maintenant, lorsque vous parcourez votre dict, vous parcourez plutôt la liste pour accéder à chaque clé de manière ordonnée sans vous soucier de la représentation de la structure du dict (qui n'a pas été conçue pour le tri).

demongolem
la source
0

Pour la façon dont la question est formulée, la plupart des réponses ici y répondent correctement.

Cependant, compte tenu de la façon dont les choses devraient être vraiment faites, en tenant compte de décennies et de décennies d'informatique, je suis totalement surpris qu'il n'y ait en fait qu'une seule réponse ici (de l' utilisateur GrantJ ) suggérant l'utilisation de conteneurs associatifs triés (conteneurs triés) qui trie les éléments en fonction de la clé à leur point d'insertion.

Cela évitera énorme impact sur les performances pour chaque appel de sort(...)(au minimum O(N*log(N)), où Nest en nombre d'éléments (logiquement, cela vaut pour toutes les solutions ici qui suggèrent d'utiliser le sort(...)). Prenez à compte que pour toutes ces solutions, l' sort(...)devront être appelé à chaque fois que la colletion doit être consultée comme triée APRÈS avoir été modifiée en ajoutant / supprimant des éléments ...

PeterB
la source
-1
l = dict.keys()
l2 = l
l2.append(0)
l3 = []
for repeater in range(0, len(l)):
    smallnum = float("inf")
    for listitem in l2:
        if listitem < smallnum:
            smallnum = listitem
    l2.remove(smallnum)
    l3.append(smallnum)
l3.remove(0)
l = l3

for listitem in l:
    print(listitem)
user7070507
la source
3
Il y a 14 autres réponses. Pouvez-vous expliquer un peu votre code et pourquoi il pourrait être meilleur que les autres solutions?
FelixSFD
Downvoted - Code assez illisible avec des noms de variables courts sans signification l, l2, l3. Semble être une tentative d'algorithme indirect et inefficace sans connaissance des fonctions standard de python, et en tout cas ne fonctionne pas lorsqu'il est testé sur un petit exemple dans la publication d'origine.
Captain Lepton