web-dev-qa-db-fra.com

python: itérer sur le dictionnaire trié par clé

J'ai un Python

steps = {1:"value1", 5:"value2", 2:"value3"}

Je dois itérer sur cet ordre est trié par la clé.

J'ai essayé ceci:

x = sorted(steps, key=lambda key: steps[key])

mais les valeurs ont disparu de x.

50
user984003

Je dois itérer sur cet ordre est trié par la clé.

Je pense que lambdas est excessif ici, essayez ceci:

>>> steps = {1:"val1", 5:"val2", 2:"val3"}
>>>
>>> for key in sorted(steps):
...     print steps[key]
...
val1
val3
val2
86

Vous devez itérer sur steps.items(), car une itération sur dict ne renvoie que ses clés.

>>> x = sorted(steps.items())
>>> x
[(1, 'value1'), (2, 'value3'), (5, 'value2')]

Itérer sur les clés triées:

>>> for key in sorted(steps):
...     # use steps[keys] to get the value
15

Vous pouvez également utiliser l'un des nombreux types de conteneurs SortedDict de Python. Ces types maintiennent automatiquement le dictionnaire trié par ordre de clé. Jetez un coup d'œil au module containerscontainers qui est une pure-Python et une implémentation rapide en C. Il existe une comparaison des performances qui compare plusieurs autres implémentations les unes aux autres.

Dans votre cas alors, vous utiliseriez:

from sortedcontainers import SortedDict
steps = SortedDict({1:"value1", 5:"value2", 2:"value3"})

# Then iterate the items:

for key, value in steps.items():
    print key, value

# Or iterate the values:

for value in steps.values():
    print value

L'itération pour les clés/valeurs/éléments fonctionne automatiquement par ordre des clés trié.

6
GrantJ

Dans le cas où vos clés ne sont pas des entiers, mais des chaînes qui doivent être analysées comme des entiers:

steps = {'1':'value1', '10': 'value0', '5':'value2', '2':'value3'}

vous pouvez utiliser quelque chose de similaire à votre solution:

for key, value in sorted(steps, key=lambda key: int(key[0])):
    print(key)

1
2
5
10
2
David Nathan

Comme l'a souligné Zagorulkin Dmitry, vous ne devez pas passer un lambda à la fonction de tri. Le comportement par défaut de la fonction de tri consiste à agir sur les touches.

steps = {1:"val1", 5:"val2", 2:"val3"}

for key in sorted(steps):
   print steps[key]
...
val1
val3
val2

Cependant, passer du lambda à la fonction de tri n’est pas un meilleur moyen d’avoir un petit bénéfice (c’est-à-dire un "dépassement"), mais c’est en fait indésirable. Cela rend le code moins lisible et plus lent, en particulier si vous voulez l’appliquer à de très grands dictionnaires ou faire plusieurs appels. Outre le fait de rendre la cible de tri plus explicite en ce qui concerne les paires (clé, valeur), son utilisation ne présente aucun avantage. Les timings suivants montrent la performance que vous obtenez lorsque vous spécifiez un lambda.

steps = {randint(0, 100000): randint(0, 100000) for _ in range(100000) } # random dict

%%timeit 
sort_list = [value for _, value in sorted(steps.items(), key=lambda item: item[0])]
1 loops, best of 3: 241 ms per loop

%%timeit 
sort_list = [steps[k] for k in sorted(steps, key=lambda k: k)]
1 loops, best of 3: 196 ms per loop

%%timeit
sort_list = [ steps[key] for key in sorted(steps) ]
10 loops, best of 3: 106 ms per loop
1
Angelos

Selon votre cas d'utilisation, il peut être judicieux de conserver un dictionnaire déjà commandé. Voir pythons OrderedDict pour plus de détails. Si vous souhaitez trier les clés sous forme d'entier, vous devez les convertir en entiers. Le meilleur moment pour le faire dépend de votre cas d'utilisation.

0
Achim