web-dev-qa-db-fra.com

Comment trier un dictionnaire par valeur?

J'ai un dictionnaire de valeurs lu à partir de deux champs d'une base de données: un champ de chaîne et un champ numérique. Le champ de chaîne est unique, il s'agit donc de la clé du dictionnaire.

Je peux trier les clés, mais comment puis-je trier en fonction des valeurs?

Remarque: J'ai lu la question Stool Overflow ici Comment trier une liste de dictionnaires en fonction d'une valeur du dictionnaire? et pourrait probablement changer mon code pour avoir une liste de dictionnaires, mais comme je n'ai pas vraiment besoin d'une liste de dictionnaires, je voulais savoir s'il existait une solution plus simple pour trier par ordre croissant ou décroissant.

3426
Gern Blanston

Il n'est pas possible de trier un dictionnaire, mais uniquement pour obtenir une représentation d'un dictionnaire qui est trié. Les dictionnaires sont intrinsèquement sans ordre, mais d'autres types, tels que les listes et les n-uplets, ne le sont pas. Vous avez donc besoin d'un type de données ordonné pour représenter les valeurs triées, qui sera une liste - probablement une liste de n-uplets.

Par exemple,

_import operator
x = {1: 2, 3: 4, 4: 3, 2: 1, 0: 0}
sorted_x = sorted(x.items(), key=operator.itemgetter(1))
_

_sorted_x_ sera une liste de nuplets triés par le deuxième élément de chaque tuple. dict(sorted_x) == x.

Et pour ceux qui souhaitent trier les clés au lieu des valeurs:

_import operator
x = {1: 2, 3: 4, 4: 3, 2: 1, 0: 0}
sorted_x = sorted(x.items(), key=operator.itemgetter(0))
_

En Python3 car le décompactage n’est pas autorisé [1] nous pouvons utiliser

_x = {1: 2, 3: 4, 4: 3, 2: 1, 0: 0}
sorted_x = sorted(x.items(), key=lambda kv: kv[1])
_

Si vous voulez que la sortie soit sous forme de dict, vous pouvez utiliser collections.OrderedDict :

_import collections

sorted_dict = collections.OrderedDict(sorted_x)
_
4292
Devin Jeanpierre

Aussi simple que: sorted(dict1, key=dict1.get)

Eh bien, il est en fait possible de faire un "tri par valeurs de dictionnaire". Récemment, j'ai dû faire cela dans un code de golf (question de débordement de pile code de golf: tableau de fréquence de mots). En résumé, le problème était du genre: à partir d'un texte, compter le nombre de fois où chaque mot est rencontré et afficher une liste des mots les plus fréquents, triés par ordre décroissant de fréquence.

Si vous construisez un dictionnaire avec les mots en tant que clés et le nombre d'occurrences de chaque mot en tant que valeur, simplifié ici comme suit:

from collections import defaultdict
d = defaultdict(int)
for w in text.split():
  d[w] += 1

vous pouvez alors obtenir une liste des mots, classés par fréquence d'utilisation avec sorted(d, key=d.get) - le tri itère sur les clés du dictionnaire, en utilisant le nombre d'occurrences de Word comme clé de tri.

for w in sorted(d, key=d.get, reverse=True):
  print w, d[w]

J'écris cette explication détaillée pour illustrer ce que les gens entendent souvent par "je peux facilement trier un dictionnaire par clé, mais comment puis-je trier par valeur" - et je pense que le PO essayait de résoudre un tel problème. Et la solution consiste à faire une sorte de liste des clés, en fonction des valeurs, comme indiqué ci-dessus.

1117
Nas Banov

Vous pouvez utiliser:

sorted(d.items(), key=lambda x: x[1])

Cela triera le dictionnaire en fonction des valeurs de chaque entrée du dictionnaire, du plus petit au plus grand.

Pour le trier par ordre décroissant, ajoutez simplement reverse=True:

sorted(d.items(), key=lambda x: x[1], reverse=True)
724
Mark

Les dictés ne peuvent pas être triés, mais vous pouvez créer une liste triée à partir d'eux.

Une liste triée de valeurs dict:

sorted(d.values())

Une liste de paires (clé, valeur), triées par valeur:

from operator import itemgetter
sorted(d.items(), key=itemgetter(1))
204

Dans le récent Python 2.7, nous avons le nouveau type OrderedDict , qui mémorise l'ordre dans lequel les éléments ont été ajoutés.

>>> d = {"third": 3, "first": 1, "fourth": 4, "second": 2}

>>> for k, v in d.items():
...     print "%s: %s" % (k, v)
...
second: 2
fourth: 4
third: 3
first: 1

>>> d
{'second': 2, 'fourth': 4, 'third': 3, 'first': 1}

Pour créer un nouveau dictionnaire commandé à partir de l’original, triez-le en fonction des valeurs:

>>> from collections import OrderedDict
>>> d_sorted_by_value = OrderedDict(sorted(d.items(), key=lambda x: x[1]))

OrderedDict se comporte comme un dict normal:

>>> for k, v in d_sorted_by_value.items():
...     print "%s: %s" % (k, v)
...
first: 1
second: 2
third: 3
fourth: 4

>>> d_sorted_by_value
OrderedDict([('first': 1), ('second': 2), ('third': 3), ('fourth': 4)])
154
mykhal

UPDATE: 5 DÉCEMBRE 2015 avec Python 3.5

Bien que j'ai trouvé la réponse acceptée utile, j'ai également été surprise de ne pas avoir mis à jour la référence OrderedDict de la norme bibliothèque collections comme alternative viable et moderne - conçue pour résoudre exactement ce type de problème.

from operator import itemgetter
from collections import OrderedDict

x = {1: 2, 3: 4, 4: 3, 2: 1, 0: 0}
sorted_x = OrderedDict(sorted(x.items(), key=itemgetter(1)))
# OrderedDict([(0, 0), (2, 1), (1, 2), (4, 3), (3, 4)])

La documentation officielle OrderedDict offre également un exemple très similaire, mais en utilisant un lambda pour la fonction de tri:

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

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

Quasiment la même chose que réponse de Hank Gay :

sorted([(value,key) for (key,value) in mydict.items()])

Ou légèrement optimisé comme suggéré par John Fouhy:

sorted((value,key) for (key,value) in mydict.items())
74
user26294

Il peut souvent être très pratique d'utiliser namedtuple. Par exemple, vous avez un dictionnaire de 'nom' en tant que clés et de 'score' en tant que valeurs et vous souhaitez effectuer un tri sur 'score':

import collections
Player = collections.namedtuple('Player', 'score name')
d = {'John':5, 'Alex':10, 'Richard': 7}

trier avec le score le plus bas en premier:

worst = sorted(Player(v,k) for (k,v) in d.items())

trier avec le score le plus élevé en premier:

best = sorted([Player(v,k) for (k,v) in d.items()], reverse=True)

Maintenant vous pouvez obtenir le nom et le score de, disons le deuxième meilleur joueur (index = 1) très pythoniquement comme ceci:

player = best[1]
player.name
    'Richard'
player.score
    7
70
Remi

A partir de Python 3.6 le dict intégré sera commandé

Bonne nouvelle, le cas d'utilisation original des paires de mappage extraites d'une base de données avec des identificateurs de chaîne uniques en tant que clés et des valeurs numériques en tant que valeurs dans un Python v3.6 + dict intégré doit désormais respecter l'insert. ordre.

Si, par exemple, les expressions de table à deux colonnes obtenues à partir d'une requête de base de données sont telles que:

SELECT a_key, a_value FROM a_table ORDER BY a_value;

serait stocké dans deux Python tuples, k_seq et v_seq (alignés par un index numérique et avec la même durée de parcours), puis:

k_seq = ('foo', 'bar', 'baz')
v_seq = (0, 1, 42)
ordered_map = dict(Zip(k_seq, v_seq))

Permet de sortir plus tard en tant que:

for k, v in ordered_map.items():
    print(k, v)

cédant dans ce cas (pour le nouveau Python 3.6 + dict intégré!):

foo 0
bar 1
baz 42

dans le même ordre par valeur de v.

Où, dans l’installation Python 3.5 sur ma machine, il produit actuellement:

bar 1
foo 0
baz 42

Détails:

Comme proposé en 2012 par Raymond Hettinger (cf. mail sur python-dev avec sujet "dictionnaires plus compacts avec itération plus rapide" ) et maintenant (en 2016) annoncé dans un mail de Victor Stinner à python-dev with subject "Python 3.6 dict devient compact et obtient une version privée; et les mots clés deviennent ordonnés" en raison du correctif/de la mise en œuvre du problème 27350 "compact et ordonné" dans Python 3.6 nous pourrons maintenant utiliser un dict intégré pour maintenir l'ordre d'insertion !!

Espérons que cela conduira dans un premier temps à une mise en œuvre de couche mince. Comme @ JimFasarakis-Hilliard l'a indiqué, certains voient les cas d'utilisation du type OrderedDict également à l'avenir. Je pense que la communauté Python va procéder à une inspection minutieuse afin de déterminer si elle résistera à l'épreuve du temps et quelles en seront les prochaines étapes.

Il est temps de repenser nos habitudes de codage pour ne pas manquer les possibilités offertes par la commande stable de:

  • Arguments de mots clés et
  • stockage dict (intermédiaire)

Le premier parce que cela facilite la répartition dans la mise en œuvre des fonctions et des méthodes dans certains cas.

La seconde incite à utiliser plus facilement dicts comme stockage intermédiaire dans les pipelines de traitement.

Raymond Hettinger a gracieusement fourni des documents expliquant " La technologie derrière Python 3.6 Dictionnaires " - extrait de son exposé San Francisco Python Meetup, 2016-DEC-08.

Et peut-être que de nombreuses pages de questions-réponses très décorées Stack Overflow recevront des variantes de cette information et que de nombreuses réponses de haute qualité nécessiteront également une mise à jour par version.

Caveat Emptor (mais aussi voir ci-dessous la mise à jour 2017-12-15):

Comme le note à juste titre @ajcr: "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é". (de la whatsnew36 ) pas de choix, mais la citation a été coupée un peu pessimiste ;-). Cela continue comme "(cela peut changer dans le futur, mais nous souhaitons avoir cette nouvelle implémentation dictée dans le langage pour quelques versions avant de changer la spécification de langage afin d’imposer une sémantique préservant les ordres pour toutes les versions actuelles et futures Python _ implémentations; cela aide également à préserver la compatibilité avec les versions antérieures du langage où l'ordre d'itération aléatoire est toujours actif, par exemple Python 3.5). "

Ainsi, comme dans certaines langues humaines (allemand, par exemple), l’utilisation façonne la langue et le testament a maintenant été déclaré ... dans whatsnew36 .

Mise à jour 2017-12-15:

Dans un mail à la liste de python-dev , Guido van Rossum a déclaré:

Faire en sorte. "Dict conserve l'ordre d'insertion" est la décision. Merci!

Ainsi, l'effet secondaire de la commande d'insertion dict dans CPython version 3.6 est en train de devenir partie intégrante de la spécification du langage (et non plus uniquement d'un détail d'implémentation). Ce fil de discussion a également révélé certains objectifs de conception distinctifs pour collections.OrderedDict, comme l'a rappelé Raymond Hettinger au cours de la discussion.

67
Dilettant

Dictionnaire donné

e = {1:39, 4:34, 7:110, 2:87}

Tri

sred = sorted(e.items(), key=lambda value: value[1])

Résultat

[(4, 34), (1, 39), (2, 87), (7, 110)]

Vous pouvez utiliser une fonction lambda pour trier les éléments par valeur et les stocker dans une variable, dans ce cas sred avec e le dictionnaire d'origine.

J'espère que ça t'as aidé!

44
bishop

J'ai eu le même problème, et je l'ai résolu comme ceci:

WantedOutput = sorted(MyDict, key=lambda x : MyDict[x]) 

(Les personnes qui répondent "Il n'est pas possible de trier un dict" n'ont pas lu la question! En fait, "Je peux trier les clés, mais comment puis-je trier en fonction des valeurs?" Signifie clairement qu'il veut une liste de les clés triées en fonction de la valeur de leurs valeurs.)

Veuillez noter que l'ordre n'est pas bien défini (les clés avec la même valeur seront dans un ordre arbitraire dans la liste de sortie).

40
jimifiki

Dans Python2.7, il suffit de faire:

from collections import OrderedDict
# regular unsorted dictionary
d = {'banana': 3, 'Apple':4, 'pear': 1, 'orange': 2}

# dictionary sorted by key
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)])

copier-coller à partir de: http://docs.python.org/dev/library/collections.html#ordereddict-examples-and-recipes

Prendre plaisir ;-)

34
sweetdream

Techniquement, les dictionnaires ne sont pas des séquences et ne peuvent donc pas être triés. Vous pouvez faire quelque chose comme

sorted(a_dictionary.values())

en supposant que la performance ne soit pas une grosse affaire.

26
Hank Gay

Si les valeurs sont numériques, vous pouvez également utiliser Counter de collections .

from collections import Counter

x = {'hello': 1, 'python': 5, 'world': 3}
c = Counter(x)
print(c.most_common())

>> [('python', 5), ('world', 3), ('hello', 1)]    
26
Ivan Sas

C'est le code:

import operator
Origin_list = [
    {"name": "foo", "rank": 0, "rofl": 20000},
    {"name": "Silly", "rank": 15, "rofl": 1000},
    {"name": "Baa", "rank": 300, "rofl": 20},
    {"name": "Zoo", "rank": 10, "rofl": 200},
    {"name": "Penguin", "rank": -1, "rofl": 10000}
]
print ">> Original >>"
for foo in Origin_list:
    print foo

print "\n>> Rofl sort >>"
for foo in sorted(Origin_list, key=operator.itemgetter("rofl")):
    print foo

print "\n>> Rank sort >>"
for foo in sorted(Origin_list, key=operator.itemgetter("rank")):
    print foo

Voici les résultats:

Original

{'name': 'foo', 'rank': 0, 'rofl': 20000}
{'name': 'Silly', 'rank': 15, 'rofl': 1000}
{'name': 'Baa', 'rank': 300, 'rofl': 20}
{'name': 'Zoo', 'rank': 10, 'rofl': 200}
{'name': 'Penguin', 'rank': -1, 'rofl': 10000}

Rofl

{'name': 'Baa', 'rank': 300, 'rofl': 20}
{'name': 'Zoo', 'rank': 10, 'rofl': 200}
{'name': 'Silly', 'rank': 15, 'rofl': 1000}
{'name': 'Penguin', 'rank': -1, 'rofl': 10000}
{'name': 'foo', 'rank': 0, 'rofl': 20000}

Rang

{'name': 'Penguin', 'rank': -1, 'rofl': 10000}
{'name': 'foo', 'rank': 0, 'rofl': 20000}
{'name': 'Zoo', 'rank': 10, 'rofl': 200}
{'name': 'Silly', 'rank': 15, 'rofl': 1000}
{'name': 'Baa', 'rank': 300, 'rofl': 20}
25
PedroMorgan

Essayez l'approche suivante. Définissons un dictionnaire appelé mydict avec les données suivantes:

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

Si on veut trier le dictionnaire par clés, on peut faire quelque chose comme:

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

Cela devrait retourner la sortie suivante:

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

Par contre, si on veut trier un dictionnaire par valeur (comme on le demande dans la question), on peut faire ce qui suit:

for key, value in sorted(mydict.iteritems(), key=lambda (k,v): (v,k)):
    print "%s: %s" % (key, value)

Le résultat de cette commande (tri du dictionnaire par valeur) devrait renvoyer ce qui suit:

bob: 1
alan: 2
danny: 3
carl: 40
23
Nathaniel Payne

Vous pouvez créer un "index inversé", également

from collections import defaultdict
inverse= defaultdict( list )
for k, v in originalDict.items():
    inverse[v].append( k )

Maintenant, votre inverse a les valeurs; chaque valeur a une liste de clés applicables.

for k in sorted(inverse):
    print k, inverse[k]
21
S.Lott

Vous pouvez utiliser le collections.Counter . Notez que cela fonctionnera pour les valeurs numériques et non numériques.

>>> x = {1: 2, 3: 4, 4:3, 2:1, 0:0}
>>> from collections import Counter
>>> #To sort in reverse order
>>> Counter(x).most_common()
[(3, 4), (4, 3), (1, 2), (2, 1), (0, 0)]
>>> #To sort in ascending order
>>> Counter(x).most_common()[::-1]
[(0, 0), (2, 1), (1, 2), (4, 3), (3, 4)]
>>> #To get a dictionary sorted by values
>>> from collections import OrderedDict
>>> OrderedDict(Counter(x).most_common()[::-1])
OrderedDict([(0, 0), (2, 1), (1, 2), (4, 3), (3, 4)])
20
Abhijit

Ceci renvoie la liste des paires clé-valeur dans le dictionnaire, triées par valeur du plus haut au plus bas:

sorted(d.items(), key=lambda x: x[1], reverse=True)

Pour le dictionnaire trié par clé, utilisez ce qui suit:

sorted(d.items(), reverse=True)

Le retour est une liste de tuples, car les dictionnaires eux-mêmes ne peuvent pas être triés.

Cela peut être à la fois imprimé ou envoyé dans un calcul ultérieur.

16
Zags

À partir de Python 3.6, les objets dict sont maintenant classés par ordre d'insertion. C'est officiellement dans les spécifications de Python 3.7.

>>> words = {"python": 2, "blah": 4, "alice": 3}
>>> dict(sorted(words.items(), key=lambda x: x[1]))
{'python': 2, 'alice': 3, 'blah': 4}

Avant cela, vous deviez utiliser OrderedDict.

documentation Python 3.7 dit:

Modifié dans la version 3.7: L'ordre des dictionnaires est garanti comme étant un ordre d'insertion. Ce comportement était le détail d'implémentation de CPython à partir de 3.6.

16
Maxime Chéramy

Vous pouvez utiliser un skip dict qui est un dictionnaire qui est trié de manière permanente par valeur.

>>> data = {1: 2, 3: 4, 4: 3, 2: 1, 0: 0}
>>> SkipDict(data)
{0: 0.0, 2: 1.0, 1: 2.0, 4: 3.0, 3: 4.0}

Si vous utilisez keys(), values() ou items(), vous effectuerez une itération dans l'ordre trié par valeur.

Il est implémenté en utilisant la skip list datastructure.

15
malthe
from Django.utils.datastructures import SortedDict

def sortedDictByKey(self,data):
    """Sorted dictionary order by key"""
    sortedDict = SortedDict()
    if data:
        if isinstance(data, dict):
            sortedKey = sorted(data.keys())
            for k in sortedKey:
                sortedDict[k] = data[k]
    return sortedDict
13
Argun

Vous pouvez également utiliser une fonction personnalisée pouvant être transmise à une clé.

def dict_val(x):
    return x[1]
x = {1: 2, 3: 4, 4: 3, 2: 1, 0: 0}
sorted_x = sorted(x.items(), key=dict_val)
12
Vishwanath Rawat

Comme l'a souligné Dilettant , Python 3.6 va maintenant garder l'ordre ! Je pensais partager une fonction que j'ai écrite qui facilite le tri d'un itérable (tuple, liste, dict). Dans ce dernier cas, vous pouvez trier les clés ou les valeurs et prendre en compte les comparaisons numériques. Uniquement pour> = 3.6!

Lorsque vous essayez d’utiliser Trier sur une valeur itérable contenant, par exemple, Les chaînes aussi bien que les ints, sortis () échoueront. Bien sûr, vous pouvez forcer la comparaison de chaînes avec str (). Cependant, dans certains cas, vous souhaitez effectuer une comparaison numérique réelle 12 est inférieur à 20 (ce qui n'est pas le cas dans la comparaison de chaînes). Alors je suis venu avec ce qui suit. Lorsque vous souhaitez une comparaison numérique explicite, vous pouvez utiliser l'indicateur num_as_num qui essaiera d'effectuer un tri numérique explicite en essayant de convertir toutes les valeurs en valeurs flottantes. Si cela réussit, il effectuera un tri numérique, sinon il aura recours à la comparaison de chaînes.

Commentaires pour amélioration ou demandes Push bienvenue.

def sort_iterable(iterable, sort_on=None, reverse=False, num_as_num=False):
    def _sort(i):
      # sort by 0 = keys, 1 values, None for lists and tuples
      try:
        if num_as_num:
          if i is None:
            _sorted = sorted(iterable, key=lambda v: float(v), reverse=reverse)
          else:
            _sorted = dict(sorted(iterable.items(), key=lambda v: float(v[i]), reverse=reverse))
        else:
          raise TypeError
      except (TypeError, ValueError):
        if i is None:
          _sorted = sorted(iterable, key=lambda v: str(v), reverse=reverse)
        else:
          _sorted = dict(sorted(iterable.items(), key=lambda v: str(v[i]), reverse=reverse))

      return _sorted

    if isinstance(iterable, list):
      sorted_list = _sort(None)
      return sorted_list
    Elif isinstance(iterable, Tuple):
      sorted_list = Tuple(_sort(None))
      return sorted_list
    Elif isinstance(iterable, dict):
      if sort_on == 'keys':
        sorted_dict = _sort(0)
        return sorted_dict
      Elif sort_on == 'values':
        sorted_dict = _sort(1)
        return sorted_dict
      Elif sort_on is not None:
        raise ValueError(f"Unexpected value {sort_on} for sort_on. When sorting a dict, use key or values")
    else:
      raise TypeError(f"Unexpected type {type(iterable)} for iterable. Expected a list, Tuple, or dict")
10
Bram Vanroy

Voici une solution utilisant Zip sur d.values() ET d.keys() . Quelques lignes en bas de ce lien (sur les objets de la vue Dictionnaire):

Cela permet la création de paires (valeur, clé) à l'aide de Zip (): pairs = Zip (d.values ​​(), d.keys ()).

Nous pouvons donc faire ce qui suit:

d = {'key1': 874.7, 'key2': 5, 'key3': 8.1}

d_sorted = sorted(Zip(d.values(), d.keys()))

print d_sorted 
# prints: [(5, 'key2'), (8.1, 'key3'), (874.7, 'key1')]
9
Scott

Utilisez ValueSortedDict à partir de dicts :

from dicts.sorteddict import ValueSortedDict
d = {1: 2, 3: 4, 4:3, 2:1, 0:0}
sorted_dict = ValueSortedDict(d)
print sorted_dict.items() 

[(0, 0), (2, 1), (1, 2), (4, 3), (3, 4)]
7
ponty

Parcourez un dict et triez-le par ordre décroissant:

$ python --version
Python 3.2.2

$ cat sort_dict_by_val_desc.py 
dictionary = dict(siis = 1, sana = 2, joka = 3, tuli = 4, aina = 5)
for Word in sorted(dictionary, key=dictionary.get, reverse=True):
  print(Word, dictionary[Word])

$ python sort_dict_by_val_desc.py 
aina 5
tuli 4
joka 3
sana 2
siis 1
6
juhoh

Si vos valeurs sont des entiers et que vous utilisez Python 2.7 ou une version ultérieure, vous pouvez utiliser collections.Counter au lieu de dict. La méthode _most_common_ vous donnera tous les éléments, triés par la valeur.

6
Petr Viktorin

Je suis venu avec celui-ci,

import operator    
x = {1: 2, 3: 4, 4:3, 2:1, 0:0}
sorted_x = {k[0]:k[1] for k in sorted(x.items(), key=operator.itemgetter(1))}

Pour Python 3.x: x.items() remplace iteritems().

>>> sorted_x
{0: 0, 1: 2, 2: 1, 3: 4, 4: 3}

Ou essayez avec collections.OrderedDict!

x = {1: 2, 3: 4, 4:3, 2:1, 0:0}
from collections import OrderedDict

od1 = OrderedDict(sorted(x.items(), key=lambda t: t[1]))
6
kiriloff

Je viens d'apprendre une compétence pertinente de Python for Everybody .

Vous pouvez utiliser une liste temporaire pour vous aider à trier le dictionnaire:

#Assume dictionary to be:
d = {'Apple': 500.1, 'banana': 1500.2, 'orange': 1.0, 'pineapple': 789.0}

# create a temporary list
tmp = []

# iterate through the dictionary and append each Tuple into the temporary list 
for key, value in d.items():
    tmptuple = (value, key)
    tmp.append(tmptuple)

# sort the list in ascending order
tmp = sorted(tmp)

print (tmp)

Si vous souhaitez trier la liste par ordre décroissant, modifiez simplement la ligne de tri d'origine en:

tmp = sorted(tmp, reverse=True)

En utilisant la compréhension par liste, la ligne serait:

#Assuming the dictionary looks like
d = {'Apple': 500.1, 'banana': 1500.2, 'orange': 1.0, 'pineapple': 789.0}
#One liner for sorting in ascending order
print (sorted([(v, k) for k, v in d.items()]))
#One liner for sorting in descending order
print (sorted([(v, k) for k, v in d.items()], reverse=True))

Exemple de sortie:

#Asending order
[(1.0, 'orange'), (500.1, 'Apple'), (789.0, 'pineapple'), (1500.2, 'banana')]
#Descending order
[(1500.2, 'banana'), (789.0, 'pineapple'), (500.1, 'Apple'), (1.0, 'orange')]
6
mcgag

Bien sûr, rappelez-vous que vous devez utiliser OrderedDict car les dictionnaires Python normaux ne conservent pas l'ordre d'origine.

from collections import OrderedDict
a = OrderedDict(sorted(originalDict.items(), key=lambda x: x[1]))

Si vous n'avez pas Python 2.7 ou supérieur, le mieux que vous puissiez faire est de parcourir les valeurs d'une fonction du générateur. (Il existe une OrderedDict pour 2.4 et 2.6 ici , mais

a) Je ne sais pas si ça marche bien

et

b) Vous devez le télécharger et l'installer bien sûr. Si vous ne disposez pas d'un accès administrateur, alors je crains que l'option ne soit supprimée.)


def gen(originalDict):
    for x, y in sorted(Zip(originalDict.keys(), originalDict.values()), key=lambda z: z[1]):
        yield (x, y)
    #Yields as a Tuple with (key, value). You can iterate with conditional clauses to get what you want. 

for bleh, meh in gen(myDict):
    if bleh == "foo":
        print(myDict[bleh])

Vous pouvez également imprimer chaque valeur

for bleh, meh in gen(myDict):
    print(bleh, meh)

N'oubliez pas de supprimer les parenthèses après l'impression si vous n'utilisez pas Python 3.0 ou supérieur.

5
ytpillai

Cela fonctionne dans 3.1.x:

import operator
slovar_sorted=sorted(slovar.items(), key=operator.itemgetter(1), reverse=True)
print(slovar_sorted)
5
iFail

Par souci d'exhaustivité, je publie une solution à l'aide de heapq . Remarque, cette méthode fonctionnera pour les valeurs numériques et non numériques

>>> x = {1: 2, 3: 4, 4:3, 2:1, 0:0}
>>> x_items = x.items()
>>> heapq.heapify(x_items)
>>> #To sort in reverse order
>>> heapq.nlargest(len(x_items),x_items, operator.itemgetter(1))
[(3, 4), (4, 3), (1, 2), (2, 1), (0, 0)]
>>> #To sort in ascending order
>>> heapq.nsmallest(len(x_items),x_items, operator.itemgetter(1))
[(0, 0), (2, 1), (1, 2), (4, 3), (3, 4)]
5
Abhijit

En raison de la nécessité de conserver la compatibilité avec les versions antérieures de Python , je pense que la solution OrderedDict est très peu judicieuse. Vous voulez quelque chose qui fonctionne avec Python 2.7 et versions antérieures.

Mais la solution de collections mentionnée dans une autre réponse est absolument superbe, car vous redéfinissez un lien entre la clé et la valeur, ce qui dans le cas des dictionnaires est extrêmement important.

Je ne suis pas d'accord avec le choix numéro un présenté dans une autre réponse, car il jette les clés.

J'ai utilisé la solution mentionnée ci-dessus (code ci-dessous) et j'ai conservé l'accès aux clés et aux valeurs. Dans mon cas, l'ordre était basé sur les valeurs, mais il importait de commander les clés après avoir commandé les valeurs.

from collections import Counter

x = {'hello':1, 'python':5, 'world':3}
c=Counter(x)
print c.most_common()


>> [('python', 5), ('world', 3), ('hello', 1)]
4
Eamonn Kenny
months = {"January": 31, "February": 28, "March": 31, "April": 30, "May": 31,
          "June": 30, "July": 31, "August": 31, "September": 30, "October": 31,
          "November": 30, "December": 31}

def mykey(t):
    """ Customize your sorting logic using this function.  The parameter to
    this function is a Tuple.  Comment/uncomment the return statements to test
    different logics.
    """
    return t[1]              # sort by number of days in the month
    #return t[1], t[0]       # sort by number of days, then by month name
    #return len(t[0])        # sort by length of month name
    #return t[0][-1]         # sort by last character of month name


# Since a dictionary can't be sorted by value, what you can do is to convert
# it into a list of tuples with Tuple length 2.
# You can then do custom sorts by passing your own function to sorted().
months_as_list = sorted(months.items(), key=mykey, reverse=False)

for month in months_as_list:
    print month
3
lessthanl0l

Thomas Cokelaer explique cela d'une manière très élégante. J'aime mentionner une note rapide de son article.

Considérons le dictionnaire suivant.

d = {"Pierre": 42, "Anne": 33, "Zoe": 24}

Pour trier sur la base des valeurs, les approches suivantes sont présentées.

sorted fonction et operator module

import operator
sorted_d = sorted(d.items(), key=operator.itemgetter(1))


sorted fonction et lambda fonction

sorted_d = sorted(d.items(), key=lambda x: x[1])


sorted fonction et retourne un dictionnaire commandé

Dans les méthodes précédentes, les objets retournés sont la liste de nuplets. Nous n’avons donc plus de dictionnaire. Nous pouvons utiliser un OrderedDict si nous préférons.

from collections import OrderedDict
sorted_d  = OrderedDict(sorted(d.items(), key=lambda x: x[1]))


sorted compréhension de la fonction et de la liste

sorted_d = sorted((value, key) for (key,value) in d.items())

Cependant, He a également fait une référence rapide de la procédure ci-dessus.

3
iNet

En plus d'utiliser le module intégré, etc., j'essaie de le résoudre manuellement ..... d'abord j'ai créé une fonction dont le travail consiste à renvoyer une valeur minimale à chaque élément du dict:

def returnminDict(_dct):
    dict_items = _dct.items()
    list_items = list(dict_items)
    init_items = list_items[0]
    for i in range(len(list_items)):
        if list_items[i][1] > init_items[1]:
           continue
        else:
           init_items = list_items[i]
    return init_items

Seconde , nous avons maintenant une fonction qui retourne un élément de valeur minimale, puis je fais un nouveau dict puis passe en boucle sur le dict:

def SelectDictSort(_dct):
    new_dict = {}
    while _dct:
        mindict = returnminDict(_dct)
        new_dict.update(dict((mindict,)))
        _dct.pop(mindict[0])
    return new_dict

j'essaie ceci SelectDictSort({2: 5, 5: 1, 4: 3, 1: 1, 0: 1, 9: 2, 8: 2}) retournera:

{0: 1, 1: 1, 5: 1, 8: 2, 9: 2, 4: 3, 2: 5}

Hmmm ... je ne sais pas ce qui est correct mais c'est ce que j'ai essayé ....

(code mis à jour de retrun new_dct à return new_dict)

1
Wira Bhakti

Utilisation de Python 3.2:

x = {"b":4, "a":3, "c":1}
for i in sorted(x.values()):
    print(list(x.keys())[list(x.values()).index(i)])
0
raton
>>> import collections
>>> x = {1: 2, 3: 4, 4:3, 2:1, 0:0}
>>> sorted_x = collections.OrderedDict(sorted(x.items(), key=lambda t:t[1]))
>>> OrderedDict([(0, 0), (2, 1), (1, 2), (4, 3), (3, 4)])

OrderedDict est la sous-classe de dict

0
liuzhijun

Cette méthode n'utilise pas lambda et fonctionne bien sur Python 3.6:

 # sort dictionary by value
d = {'a1': 'fsdfds', 'g5': 'aa3432ff', 'ca':'zz23432'}
def getkeybyvalue(d,i):
    for k, v in d.items():
        if v == i:
            return (k)

sortvaluelist = sorted(d.values())

# In >> Python 3.6+ << the INSERTION-ORDER of a dict is preserved. That is,
# when creating a NEW dictionary and filling it 'in sorted order',
# that order will be maintained.
sortresult ={}
for i1 in sortvaluelist:   
    key = getkeybyvalue(d,i1)
    sortresult[key] = i1
print ('=====sort by value=====')
print (sortresult)
print ('=======================')
0
xiyurui