valeurs - trier une liste de dictionnaire python




Comment trier un dictionnaire par valeur? (20)

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 une version intégrée de Python v3.6 + dict devrait maintenant respecter l'ordre d'insertion.

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 tuples Python, k_seq et v_seq (alignés par un index numérique et avec la même durée 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 en tant que:

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

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

foo 0
bar 1
baz 42

dans le même ordre par valeur de v.

Où, dans l’installation de 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 le sujet "dictionnaires plus compacts avec itération plus rapide" ) et maintenant (en 2016) annoncé dans un courrier de Victor Stinner à python-dev avec le sujet "Python 3.6 devient dict compact et obtient une version privée; et les mots clés deviennent ordonnés "en raison du correctif / implémentation du problème 27350 " Dict 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 implémentation de la 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 dans son ensemble va soigneusement inspecter, si cela va résister à l'épreuve du temps, et quelles 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 les dict comme stockage intermédiaire dans les pipelines de traitement.

Raymond Hettinger a gracieusement fourni une documentation expliquant « Le dictionnaire technologique derrière les dictionnaires Python 3.6 » - tirée de sa présentation du groupe de rencontres San Francisco Python 2016-DÉC-08.

Et peut-être que de nombreuses pages de questions et 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é". (from the 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 dans le langage pour quelques versions avant de changer la spécification du langage pour rendre obligatoire la sémantique préservant les ordres pour toutes les implémentations actuelles et futures de Python; ceci aussi. aide à préserver la rétrocompatibilité avec les anciennes versions du langage où l'ordre d'itération aléatoire est toujours actif (par exemple, Python 3.5). "

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

Mise à jour 2017-12-15:

Dans un courrier à 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 fait maintenant partie des spécifications du langage (et non plus uniquement du détail de l’implémentation). Ce fil de discussion a également révélé certains objectifs de conception pour les collections.OrderedDict comme l'a rappelé Raymond Hettinger au cours de la discussion.

J'ai un dictionnaire de valeurs lues à 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 relative au débordement de pile. Comment trier une liste de dictionnaires en fonction 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 s'il existe une solution plus simple.


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û le faire dans un code de golf (question de débordement de pile de code de golf: tableau de fréquence de mots ). En résumé, le problème était du genre: à partir d'un texte, comptez la fréquence à laquelle chaque mot est rencontré et affichez 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 comme clés et le nombre d’occurrences de chaque mot comme valeur, simplifiez 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 mots 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, basée sur les valeurs, comme indiqué ci-dessus.


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}

Cela renvoie la liste des paires clé-valeur du dictionnaire, trié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 à la fois imprimé ou envoyé dans un calcul ultérieur.


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, sred avec le dictionnaire d'origine.

J'espère que cela pourra aider!


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 à partir de: http://docs.python.org/dev/library/collections.html#ordereddict-examples-and-recipes

Prendre plaisir ;-)


Il n’est pas possible de trier un dictionnaire, mais uniquement d’obtenir une représentation d’un dictionnaire 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 tuples 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_by_value = sorted(x.items(), key=lambda kv: kv[1])

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

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]))

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))

Quasiment 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())


Si les valeurs sont numériques, vous pouvez également utiliser Compteur 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)]    

Utilisez ValueSortedDict 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)]

Voici une solution utilisant zip sur d.values() et d.keys() . Quelques lignes plus bas, ce lien (sur les objets de la vue Dictionnaire) est:

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')]

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]

Vous pouvez utiliser la fonction triée de Python

sorted(iterable[, cmp[, key[, reverse]]])

Ainsi, vous pouvez utiliser:

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

Visitez ce lien pour plus d'informations sur la fonction triée: https://docs.python.org/2/library/functions.html#sorted


Vous pouvez utiliser un dictionnaire qui est un dictionnaire trié en permanence 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 structure de données de la liste de saut.


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.


Comme l'a souligné Dilettant , Python 3.6 va maintenant garder la commande ! 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. Seulement pour> = 3.6!

Quand vous essayez d’utiliser Trier sur une variable itérable contenant, par exemple, des chaînes de caractères, ainsi que ints, trié () échouera. Bien sûr, vous pouvez forcer la comparaison de chaînes avec str (). Toutefois, dans certains cas, vous souhaitez effectuer une comparaison numérique réelle12est inférieur à 20(ce qui n'est pas le cas dans la comparaison de chaîne). Alors je suis venu avec ce qui suit. Lorsque vous souhaitez une comparaison numérique explicite, vous pouvez utiliser l'indicateur num_as_numqui essaiera d'effectuer un tri numérique explicite en essayant de convertir toutes les valeurs en flottants. Si cela réussit, il effectuera un tri numérique, sinon il aura recours à la comparaison de chaînes.

Les commentaires d'amélioration ou les demandes push sont les bienvenus.

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 une version plus récente, vous pouvez utiliser à la collections.Counterplace de dict. La most_commonméthode vous donnera tous les éléments, triés par la valeur.







dictionary