web-dev-qa-db-fra.com

dictionnaire de tri python 3

Je travaille sur python 3.2.2 . Je me suis cassé la tête plus de 3 heures pour trier un dictionnaire par ses clés . J'ai réussi à en faire une liste triée avec 2 membres d'argument dictionnaire trié à la fin.

C'est ce que j'ai pensé:

myDic={10: 'b', 3:'a', 5:'c'}
sorted_list=sorted(myDic.items(), key=lambda x: x[0])

Mais peu importe ce que je ne peux pas faire un dictionnaire de cette liste triée. Comment je fais ça? Merci!

26
Jjang

dict ne conserve pas l'ordre de ses éléments. Ce dont vous avez besoin est un OrderedDict: http://docs.python.org/library/collections.html#collections.OrderedDict

modifier

Exemple d'utilisation:

>>> from collections import OrderedDict
>>> a = {'foo': 1, 'bar': 2}
>>> a
{'foo': 1, 'bar': 2}
>>> b = OrderedDict(sorted(a.items()))
>>> b
OrderedDict([('bar', 2), ('foo', 1)])
>>> b['foo']
1
>>> b['bar']
2
36
Mikołaj Siedlarek

Je ne pense pas que vous voulez un OrderedDict. On dirait que vous préférez un SortedDict , c’est un dict qui conserve ses clés dans l’ordre trié. Le module sortContainers fournit exactement ce type de données. Il est écrit en pur-Python, implémentation rapide en tant que C, a une couverture de 100% et des heures de stress.

L'installation est facile avec pip:

pip install sortedcontainers

Notez que si vous ne pouvez pas pip install, vous pouvez simplement extraire les fichiers source du référentiel open-source.

Ensuite, votre code est simplement:

from sortedcontainers import SortedDict
myDic = SortedDict({10: 'b', 3:'a', 5:'c'})
sorted_list = list(myDic.keys())

Le module de conteneurs triés maintient également une comparaison de performances avec d'autres implémentations populaires.

15
GrantJ

La variable dicts ordinaire de Python ne peut pas être utilisée pour fournir les clés/éléments dans un ordre spécifique. Pour cela, vous pouvez utiliser le type OrderedDict du module collections. Notez que le type OrderedDict conserve simplement un enregistrement de l'ordre d'insertion. Avant d'initialiser le dictionnaire, vous devez trier les entrées si vous souhaitez que les vues/itérateurs suivants renvoient les éléments dans l'ordre à chaque fois. Par exemple:

>>> myDic={10: 'b', 3:'a', 5:'c'}
>>> sorted_list=sorted(myDic.items(), key=lambda x: x[0])
>>> myOrdDic = OrderedDict(sorted_list)
>>> myOrdDic.items()
[(3, 'a'), (5, 'c'), (10, 'b')]
>>> myOrdDic[7] = 'd'
>>> myOrdDic.items()
[(3, 'a'), (5, 'c'), (10, 'b'), (7, 'd')]

Si vous souhaitez conserver un ordre correct pour les éléments nouvellement ajoutés, vous devez vraiment utiliser une structure de données différente, par exemple un arbre/tas binaire. Cette approche consistant à créer une liste triée et à l'utiliser pour initialiser une nouvelle instance OrderedDict() est simplement inefficace si vos données ne sont pas complètement statiques.

Edit: Ainsi, si le tri des données a simplement pour but de l’imprimer dans l’ordre, dans un format ressemblant à un objet python dict, il suffira de l’opération suivante:

def pprint_dict(d):
    strings = []
    for k in sorted(d.iterkeys()):
        strings.append("%d: '%s'" % (k, d[k]))
    return '{' + ', '.join(strings) + '}'

Notez que cette fonction n’est pas flexible avec les types de paires clé/valeur de la clé (c’est-à-dire qu’elle s'attend à ce que les clés soient des entiers et les valeurs correspondantes des chaînes). Si vous avez besoin de plus de flexibilité, utilisez plutôt strings.append("%s: %s" % (repr(k), repr(d[k]))).

11
Greg E.

Une solution moderne et rapide pour Python 3.7. Peut aussi fonctionner avec certains interprètes de Python 3.6.

TLDR

Pour trier un dictionnaire par clé, utilisez:

sorted_dict = {k: disordered[k] for k in sorted(disordered)}

Presque trois fois plus rapide que la réponse acceptée; probablement plus lorsque vous incluez des importations.

Commentaire sur la réponse acceptée

L'exemple dans la réponse acceptée au lieu d'itérer sur les clés uniquement - avec le paramètre key de sorted() ou le comportement par défaut de dict itération - itère sur les tuples (key, value), ce qui s'avère étonnamment beaucoup plus lent que la comparaison des clés et l'accès aux éléments de dictionnaire une liste de compréhension.

Comment trier par clé en Python 3.7

Le gros changement dans Python 3.7 est que les dictionnaires sont maintenant ordonnés par défaut .

  • Vous pouvez générer un dict trié en utilisant des interprétations dict.
  • Utiliser OrderedDict peut être préférable pour des raisons de compatibilité.
  • N'utilisez pas sorted(d.items()) sans key.

Voir:

disordered = {10: 'b', 3: 'a', 5: 'c'}

# sort keys, then get values from original - fast
sorted_dict = {k: disordered[k] for k in sorted(disordered)}

# key = itemgetter - slower
from operator import itemgetter
key = itemgetter(0)
sorted_dict = {k: v for k, v in sorted(disordered.items(), key=key)}

# key = lambda - the slowest
key = lambda item: item[0]
sorted_dict = {k: v for k in sorted(disordered.items(), key=key)} 

Résultats de chronométrage:

Best for {k: d[k] for k in sorted(d)}: 7.507327548999456
Best for {k: v for k, v in sorted(d.items(), key=key_getter)}: 12.031082626002899
Best for {k: v for k, v in sorted(d.items(), key=key_lambda)}: 14.22885995300021

Best for dict(sorted(d.items(), key=key_getter)): 11.209122000000207
Best for dict(sorted(d.items(), key=key_lambda)): 13.289728325995384
Best for dict(sorted(d.items())): 14.231471302999125

Best for OrderedDict(sorted(d.items(), key=key_getter)): 16.609151654003654
Best for OrderedDict(sorted(d.items(), key=key_lambda)): 18.52622927199991
Best for OrderedDict(sorted(d.items())): 19.436101284998585

Code de test:

from timeit import repeat

setup_code = """
from operator import itemgetter
from collections import OrderedDict
import random
random.seed(0)
d = {i: chr(i) for i in [random.randint(0, 120) for repeat in range(120)]}
key_getter = itemgetter(0)
key_lambda = lambda item: item[0]
"""

cases = [
    # fast
    '{k: d[k] for k in sorted(d)}',
    '{k: v for k, v in sorted(d.items(), key=key_getter)}',
    '{k: v for k, v in sorted(d.items(), key=key_lambda)}',
    # slower
    'dict(sorted(d.items(), key=key_getter))',
    'dict(sorted(d.items(), key=key_lambda))',
    'dict(sorted(d.items()))',
    # the slowest 
    'OrderedDict(sorted(d.items(), key=key_getter))',
    'OrderedDict(sorted(d.items(), key=key_lambda))',
    'OrderedDict(sorted(d.items()))',
]

for code in cases:
    times = repeat(code, setup=setup_code, repeat=3)
    print(f"Best for {code}: {min(times)}")
10
krassowski

Avec Python 3.7, je pouvais faire ceci:

>>> myDic={10: 'b', 3:'a', 5:'c'}
>>> sortDic = sorted(myDic.items())
>>> print(dict(sortDic))
{3:'a', 5:'c', 10: 'b'}

Si vous voulez une liste de tuples:

>>> myDic={10: 'b', 3:'a', 5:'c'}
>>> sortDic = sorted(myDic.items())
>>> print(sortDic)
[(3, 'a'), (5, 'c'), (10, 'b')]
1
Prashant

Une solution moderne à ce problème? J'ai travaillé dessus avec:

    order = sorted([ job['priority'] for job in self.joblist ])
    sorted_joblist = []
    while order:
        min_priority = min(order)
        for job in self.joblist:
            if job['priority'] == min_priority:
                sorted_joblist += [ job ]
                order.remove(min_priority)
    self.joblist = sorted_joblist

Le joblist est formaté de la façon suivante: }]

  • Fondamentalement, je crée une liste (ordre) avec tous les éléments par lesquels je veux trier le dict
  • puis j'itère cette liste et le dict, quand je trouve l'article sur le dict, je l'envoie à un nouveau dict et supprime l'article de 'commande'.

Cela semble fonctionner, mais je suppose qu'il existe de meilleures solutions.

1
Flavio Carmo

J'aime python numpy pour ce genre de choses! par exemple:

r=readData()
nsorted = np.lexsort((r.calls, r.slow_requests, r.very_slow_requests, r.stalled_requests))

J'ai un exemple d'importation de données CSV dans numpy et de classement par priorité de colonne . https://github.com/unixunion/toolbox/blob/master/python/csv-numpy.py

Kegan

0
unixunion

La réponse acceptée fonctionne définitivement, mais manque un point important.

Le PO demande un dictionnaire trié par sa keys, ce n’est tout simplement pas possible et ce que OrderedDict fait.

OrderedDict maintient le contenu du dictionnaire dans l'ordre d'insertion. Premier élément inséré, deuxième élément inséré, etc.

>>> d = OrderedDict()
>>> d['foo'] = 1
>>> d['bar'] = 2
>>> d
OrderedDict([('foo', 1), ('bar', 2)])

>>> d = OrderedDict()
>>> d['bar'] = 2
>>> d['foo'] = 1
>>> d
OrderedDict([('bar', 2), ('foo', 1)])

Par conséquent, je ne pourrai pas vraiment trier le dictionnaire inplace , mais simplement créer un nouveau dictionnaire dans lequel l'ordre d'insertion correspond à l'ordre des clés. Ceci est explicite dans la réponse acceptée où le nouveau dictionnaire est b.

Cela peut être important si vous conservez l'accès aux dictionnaires via des conteneurs. Ceci est également important si vous souhaitez modifier le dictionnaire ultérieurement en ajoutant ou en supprimant des éléments: ils ne seront pas insérés dans l'ordre des clés mais à la fin du dictionnaire.

>>> d = OrderedDict({'foo': 5, 'bar': 8})
>>> d
OrderedDict([('foo', 5), ('bar', 8)])
>>> d['alpha'] = 2
>>> d
OrderedDict([('foo', 5), ('bar', 8), ('alpha', 2)])

Maintenant, que signifie avoir un dictionnaire trié par ses clés? Cela ne fait aucune différence lorsque vous accédez à des éléments à l'aide de touches, cela n'a d'importance que lorsque vous effectuez une itération sur des éléments. Faire de cette propriété une propriété du dictionnaire lui-même semble excessif. Dans de nombreux cas, il suffit de trier les clés () lors d’une itération.

Cela signifie que cela équivaut à faire:

>>> d = {'foo': 5, 'bar': 8}
>>> for k,v in d.iteritems(): print k, v

sur un hypothétique trié par dictionnaire clé ou:

>>> d = {'foo': 5, 'bar': 8}
>>> for k, v in iter((k, d[k]) for k in sorted(d.keys())): print k, v

Bien sûr, il n’est pas difficile d’encapsuler ce comportement dans un objet en surchargeant les itérateurs et en maintenant une liste de clés triée. Mais c'est probablement exagéré.

0
kriss

Peut-être pas si bon que ça, mais j'ai compris ceci:

def order_dic(dic):
    ordered_dic={}
    key_ls=sorted(dic.keys())
    for key in key_ls:
        ordered_dic[key]=dic[key]
    return ordered_dic
0
Maz1978