python: iterate over dictionary sorted by key

I have a Python dictionary

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

I need to iterate over this sorted by key.

I tried this:

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

but the values are gone from x.

90466 次浏览

You need to iterate over steps.items(), because an iteration over dict only returns its keys.

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

Iterate over sorted keys:

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

I need to iterate over this is sorted order by the key.

I think lambdas is overkill here, try this:

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

Depending on your use case, it might be an option to hold an already ordered dictionary. See pythons OrderedDict for details. If you want to sort the keys as integer, you have to convert them to integers. The best moment to do so depends on your use case.

You can also use one of Python's many SortedDict container types. These types automatically maintain the dictionary sorted in key-order. Take a look at the sortedcontainers module which is pure-Python and fast-as-C-implementations. There's a performance comparison that benchmarks several other implementations against each other.

In your case then, you'd use:

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

Iteration for keys/values/items works automatically by sorted key order.

Like pointed by Zagorulkin Dmitry, you should not pass a lambda to the sorting function. The sorting function default behaviour is to act on the keys.

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


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

However, passing the lambda to the sorting function isn't a better operation of small benefit (i.e. an 'overkill'), but it is actually undesired. It makes the code less readable and it also slower, particularly if you are going to apply it to very large dictionaries or make the call multiple times. Other than making the sorting target more explicit in respect to the (key, value) pairs, there is no benefit to using it. The following timings show the performance hit you get when specifying a 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

In case your keys are not integers, but strings that should be parsed as integers:

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

you can use something similar to your solution:

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


1
2
5
10