Comment trier un dictionnaire par valeur?
j'ai un dictionnaire de valeurs lu à partir de deux champs dans une base de données: un champ de chaîne et un champ numérique. Le champ string est unique, donc c'est la clé du dictionnaire.
je peux trier sur les touches, mais comment puis-je trier sur la base des valeurs?
Note: j'ai lu Stack Overflow question comment trier une liste de dictionnaires par des valeurs du dictionnaire en Python? 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 si il y a une solution plus simple.
30 réponses
Il n'est pas possible de les trier un dictionnaire, seulement pour obtenir une représentation d'un dictionnaire, qui est triée. Les dictionnaires sont intrinsèquement sans ordre, mais d'autres types, comme les listes et les tuples, ne le sont pas. Vous avez donc besoin d'un type de données ordonné pour représenter les valeurs triées, qui seront une liste-probablement une liste de tuples.
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 tuples triés par le deuxième élément dans chaque tuple. dict(sorted_x) == x
.
et pour ceux qui souhaitent trier des clés au lieu de 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 puisque le déballage n'est pas autorisé [1] nous pouvons utiliser
x = {1: 2, 3: 4, 4: 3, 2: 1, 0: 0}
sorted_by_value = sorted(x.items(), key=lambda kv: kv[1])
aussi simple que: sorted(dict1, key=dict1.get)
Eh bien, il est en fait possible de faire un "tri par les valeurs du dictionnaire". Récemment, j'ai dû faire cela dans un Golf de Code (question de débordement de pile golf de code: Carte de fréquence de mot ). Abrégé, le problème était du genre: à partir d'un texte, compter combien de fois chaque mot est rencontré et afficher une liste des premiers mots, classés par fréquence Décroissante.
si vous construisez un dictionnaire avec les mots-clés et le nombre d'occurrences de chaque mot en valeur, simplifiée ici:
from collections import defaultdict
d = defaultdict(int)
for w in text.split():
d[w] += 1
alors vous pouvez obtenir une liste des mots, classés par fréquence d'utilisation avec sorted(d, key=d.get)
- le sort itère au-dessus des clés du dictionnaire, en utilisant le nombre de occurrences de mot comme une clé de sort .
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 veulent souvent dire par " je peux facilement trier un dictionnaire par clé, mais comment puis - je Trier par valeur" - et je pense que L'OP essayait de traiter un tel problème. Et la solution est de faire une sorte de liste des clés, basée sur les valeurs, comme indiqué ci-dessus.
vous pouvez utiliser:
sorted(d.items(), key=lambda x: x[1])
cela va trier le dictionnaire par les valeurs de chaque entrée dans le dictionnaire de la plus petite à la plus grande.
Dicts ne peuvent pas être triés, mais vous pouvez construire une liste triée 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))
dans le récent Python 2.7, nous avons le nouveau type OrderedDict , qui se souvient de 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 faire un nouveau dictionnaire commandé à partir de l'original, le tri par les valeurs:
>>> from collections import OrderedDict
>>> d_sorted_by_value = OrderedDict(sorted(d.items(), key=lambda x: x[1]))
La OrderedDict se comporte comme un normal dict:
>>> 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)])
mise à jour: 5 décembre 2015 en utilisant Python 3.5
bien que j'ai trouvé la réponse acceptée utile, j'ai été surpris qu'elle n'ait pas été mise à jour pour référence OrderedDict de la bibliothèque standard collections module comme une alternative viable et moderne - conçu 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)])
L'officiel OrderedDict documentation offre un exemple très similaire aussi, 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)])
, Il peut souvent être très pratique à utiliser namedtuple . Par exemple, vous avez un dictionnaire de 'nom' comme clés et 'score' comme valeurs et vous voulez trier sur 'score':
import collections
Player = collections.namedtuple('Player', 'score name')
d = {'John':5, 'Alex':10, 'Richard': 7}
tri avec la note la plus basse en premier:
worst = sorted(Player(v,k) for (k,v) in d.items())
tri 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
à peu près la même chose que la réponse de Hank Gay;
sorted([(value,key) for (key,value) in mydict.items()])
ou optimisé un peu comme suggéré par John Fouhy;
sorted((value,key) for (key,value) in mydict.items())
à partir de Python 3.6 le dict intégré sera commandé
bonne nouvelle, donc le cas d'utilisation original de l'OP de paires de cartes extraites d'une base de données avec des ID de chaîne unique comme clés et des valeurs numériques comme valeurs dans une v3 Python intégrée.6 + dict, doit maintenant respecter l'ordre d'insertion.
Si dire la résultante de deux colonne d'expressions de table à partir d'une requête de base de données comme:
SELECT a_key, a_value FROM a_table ORDER BY a_value;
serait stocké dans deux tuples Python, k_seq et v_seq (alignés par index numérique et avec la même longueur de cours), puis:
k_seq = ('foo', 'bar', 'baz')
v_seq = (0, 1, 42)
ordered_map = dict(zip(k_seq, v_seq))
permet de sortir plus tard comme:
for k, v in ordered_map.items():
print(k, v)
donnant 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 le Python 3.5 installer sur ma machine il donne actuellement:
bar 1
foo 0
baz 42
détails:
comme proposé en 2012 par Raymond Hettinger (cf. mail on python-dev with subject "More compact dictionaries with faster iteration" ) et maintenant (en 2016) annoncé dans un mail par Victor Stinner à python-dev avec sujet "Python 3.6 dict devient compact et obtient une version privée; et les mots clés deviennent commandés" en raison de la correction/mise en œuvre de la question 27350 " Dict Compact et commandé" en Python 3.6 nous allons maintenant pouvoir, utiliser un dict intégré pour maintenir l'ordre d'insertion!!
avec un peu de chance, cela conduira à une couche fine ordonnant la mise en œuvre du Décret en tant que première étape. Comme @JimFasarakis-Hilliard l'a indiqué, certains voient des cas d'utilisation pour le type OrderedDict aussi à l'avenir. Je pense que la communauté Python dans son ensemble va soigneusement inspecter, si cela résistera à l'épreuve du temps, et quelles seront les prochaines étapes.
il est temps de repenser notre habitudes de codage à ne pas manquer les possibilités ouvertes par la commande stable de:
- Keyword arguments et
- (intermédiaire) stockage de dict
la première parce qu'elle facilite l'exécution des fonctions et des méthodes dans certains cas.
le second comme il encourage à utiliser plus facilement dict
s comme stockage intermédiaire dans les pipelines de traitement.
Raymond Hettinger a gentiment fourni de la documentation expliquant " la technologie derrière les dictionnaires Python 3.6 " - de sa présentation de San Francisco Python Meetup Group 2016-DEC-08.
et peut-être tout à fait certaines pages de questions et réponses empilées décorées haut recevront des variantes de cette information et de nombreuses réponses de haute qualité nécessiteront une mise à jour de la version par.
caveat Emptor (mais aussi voir ci-dessous mise à jour) 2017-12-15):
comme @ajcr le note à juste titre: "l'aspect de la préservation de l'ordre de cette nouvelle mise en œuvre est considéré comme un détail de mise en œuvre et ne devrait pas être invoqué."(à partir de la whatsnew36 ) ne nit de la cueillette, de mais la citation a été coupé un peu pessimiste ;-). Il continue comme " (cela peut changer dans le futur, mais il est souhaitable d'avoir cette nouvelle implémentation dict dans la langue pour quelques versions avant de changer le spécification du langage pour rendre obligatoire la sémantique de l'ordre pour toutes les implémentations actuelles et futures de Python; cela permet également de préserver la rétrocompatibilité avec les anciennes versions du langage où l'ordre d'itération aléatoire est encore en vigueur, par exemple Python 3.5)."
comme dans certaines langues humaines (par exemple l'Allemand), l'usage forme la langue, et le testament a maintenant été déclaré ... in whatsnew36 .
mise à jour 2017-12-15:
Dans un un mail à la python-dev liste , Guido van Rossum a déclaré:
. "Dict garde l'ordre d'insertion" est le règlement. Merci!
ainsi, la version 3.6 CPython effet secondaire de la commande d'insertion dict fait maintenant partie de la spécification de langue (et non plus seulement un détail d'implémentation). Ce fil de courrier a également fait apparaître certains objectifs de conception distinctifs pour collections.OrderedDict
comme L'a rappelé Raymond Hettinger lors de la discussion.
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 choses par valeur et les stocker traités à l'intérieur d'une variable, dans ce cas sred avec e le dictionnaire original.
Espère que ça aide!
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 gens qui répondent" il n'est pas possible de trier un dict " n'ont pas lu la question! En fait, "je peux trier selon les clés, mais comment puis-je trier selon les valeurs?"signifie clairement qu'il veut une liste des clés triées en fonction de la valeur de leurs valeurs.)
s'il vous plaît noter que l'ordre n'est pas bien défini (clés avec la même valeur sera dans un ordre arbitraire dans le liste de sortie).
en Python 2.7, faites simplement:
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 de: http://docs.python.org/dev/library/collections.html#ordereddict-examples-and-recipes
Profiter ;-)
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}
Mdr
{'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}
si les valeurs sont numériques, vous pouvez également utiliser le compteur des 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)]
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 n'est pas une grosse affaire.
vous pouvez créer un "index inversé", aussi
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 des clés.
for k in sorted(inverse):
print k, inverse[k]
vous pouvez utiliser les collections .Le compteur . Remarque: cela fonctionne 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)])
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 voulait trier le dictionnaire par touches, on pourrait 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 l'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 en fonction de la valeur) doit renvoyer ce qui suit:
bob: 1
alan: 2
danny: 3
carl: 40
Vous pouvez utiliser un sauter dict qui est un dictionnaire qui est en permanence triées 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()
alors vous itérerez dans l'ordre trié par la valeur.
il est mis en œuvre en utilisant l'infrastructure de données skip list .
renvoie la liste des paires de valeurs clés dans le dictionnaire, classées par valeur, du plus élevé 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 imprimé ou envoyé dans d'autres calculs.
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
Vous pouvez également utiliser la fonction personnalisée qui peut être transmis à la 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)
une autre façon de faire est d'utiliser la fonction labmda
x = {1: 2, 3: 4, 4: 3, 2: 1, 0: 0}
sorted_x = sorted(x.items(), key=lambda t: t[1])
Voici une solution utilisant zip sur d.values()
et d.keys()
. Quelques lignes sur ce lien (sur les objets de Dictionary view) est:
cela permet la création de paires (valeur, clé) en utilisant zip(): pairs = zip(D. valeurs (), D. keys()).
donc nous pouvons 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')]
itérer à travers un dict et le Trier par ses valeurs dans l'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
j'ai trouvé 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()
remplaçant 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]))
vous pouvez utiliser la fonction triée de Python
sorted(iterable[, cmp[, key[, reverse]]])
vous pouvez donc utiliser:
sorted(dictionary.items(),key = lambda x :x[1])
visitez ce lien pour plus d'information sur la fonction triée: https://docs.python.org/2/library/functions.html#sorted
bien sûr, rappelez-vous, vous devez utiliser OrderedDict
parce que les dictionnaires Python réguliers ne respectent 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 plus, le mieux que vous pouvez faire est d'itérer les valeurs dans une fonction de générateur. (Il y a une ordonnance pour 2.4 et 2.6 ici , mais
a) I don't know about how well it works
et
b) You have to download and install it of course. If you do not have administrative access, then I'm afraid the option's out.)
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 toutes les valeurs
for bleh, meh in gen(myDict):
print(bleh,meh)
n'oubliez pas de supprimer les parenthèses après impression si vous n'utilisez pas Python 3.0 ou plus
comme le souligne Dilettant , Python 3.6 va maintenant garder l'ordre ! J'ai pensé partager une fonction que j'ai écrite qui facilite le tri d'une itérable (tuple, list, dict). Dans ce dernier cas, vous pouvez trier sur les clés ou les valeurs, et il peut prendre la comparaison numérique en compte. seulement pour > = 3,6!
lorsque vous essayez d'utiliser tried sur un itérable qui contient par exemple des chaînes de caractères ainsi que des ints, sorted() échouera. Bien sûr, vous pouvez forcer la comparaison des chaînes de caractères Avec str(). Cependant, dans certains cas, vous voulez faire réel comparaison numérique où 12
est plus petit que 20
(ce qui n'est pas le cas dans la comparaison de chaîne de caractères). Donc, je suis venu avec la suivante. Lorsque vous voulez une comparaison numérique explicite, vous pouvez utiliser le drapeau num_as_num
qui va essayer de faire le tri numérique explicite en essayant de convertir toutes les valeurs en flotteurs. Si cela réussit, il va faire du numérique le tri, sinon on aura recours à la comparaison des cordes.
Commentaires pour l'amélioration de la ou pousser les demandes de 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")
si vos valeurs sont des entiers, et que vous utilisez Python 2.7 ou plus récent, vous pouvez utiliser collections.Counter
au lieu de dict
. La méthode most_common
vous donnera tous les articles, Classés par leur valeur.