开发者

How to sort dictionaries by keys in Python

Can anyone tell me how I can sort this:

{'a': [1, 2, 3], 'c': ['one', 'two'], 'b': ['blah', 'bhasdf', 'asdf'], 'd': ['asdf', 'wer', 'asdf', 'zxcv']}

into

{'a': [1, 2, 3], 'b': ['blah', 'bhasdf', 'asdf'], 'c': ['one', 'two'],'d': ['asdf', 'wer', 'asdf', 'zxcv']}

? Thanks!

UPDATE 1, code sample:

So I am doing linguistics. One article is broken down to words that are stored in a database and have all kinds of properties including para ID and sentence ID. The task: trying to rebuild the original text.

Get 500 consecutive words from DB

words = Words.objects.all()[wordId:wordId+500]
# I first create paragraphs, through which I can loop later in my django template,
# and in each para will be a list of words (also dictionaries). 
# So i am trying to get a dictionary with values that are lists of dictionaries. 
# 'pp' i make just for shorthanding a long-named variable.
paras={}
para_high = para_low =  words[0].belongs_to_paragraph
for w in words:
    last_word = w
    pp = w.belongs_to_paragraph
    if pp >para_high:
        para_high = pp
    if pp < para_low:
        para_low = pp
    if pp in paras:
        paras[pp].append(w)
    else:
        list = [w]
        paras[pp] = list
# Since there are blank lines between paragraphs, in rebuilding the text as it 
    #  looked originally, I need to insert blank lines. 
    # Since i have the ID's of the paragraphs and they go somewhat like that: 1,3,4,8,9 
    #(the gaps between 1 & 3 and 4 & 8 i have to fill in with something else, 
    # which is why i had para_low and para_high to loop the range. 
isbr = True
for i in range(para_low, para_high+1):
    if i in paras:
        isbr = True
    else:
        if isbr:
            paras[i]=['break']
            isbr = False
        else:
            paras[i]=[]

At this point, however, if I try to loop the dict and rebuild the text, some later id'd paragraphs come before previous ones, and that just doesn't do it.

UPDATE 2, loop code:

        {% for k,v in wording.iteritems()  %}
        {% if v[0] == 'break' %}
        <br/>
        {% else %}
        </div><div class="p">{% for word in v %}{% if word.special==0%} {% endif %}<span class="word {% if word.special == 0%}clickable{% endif%}" wid="{{word.id}}" special="{{word.specia开发者_开发问答l}}" somethingElse={{word.somethingElse}}>{{ word.word }}</span>{% endfor %}
        {% endif %}
    {% endfor %}


Dicts don't have an order.

You can call sorted but this just gives you a sorted list of the keys:

>>> sorted(d)
['a', 'b', 'c', 'd']

You can treat it as an iterable and sort the key-value tuples, but then you've just got a list of tuples. That's not the same as a dict.

>>> sorted(d.items())
[
 ('a', [1, 2, 3]),
 ('b', ['blah', 'bhasdf', 'asdf']),
 ('c', ['one', 'two']),
 ('d', ['asdf', 'wer', 'asdf', 'zxcv'])
]

If you are using Python 2.7 or newer you could also consider using an OrderedDict.

dict subclass that remembers the order entries were added

For example:

>>> d = collections.OrderedDict(sorted(d.items()))
>>> for k, v in d.items():
>>>     print k, v
a [1, 2, 3]
b ['blah', 'bhasdf', 'asdf']
c ['one', 'two']
d ['asdf', 'wer', 'asdf', 'zxcv']


The correct answer is that if you want the items of a dictionary in a sorted order, you should use the sorted() function when you loop over the dictionary:

for k, v in sorted(d.items()):
    print k, ':', v

or

for k in sorted(d):
   print d[k]

Or similar.

The OrderedDict mentioned is for dictionaries that have an order. And order is not the same as a sorting. You can create a sorted OrderedDict, yes, but as soon as you add a new key it is no longer sorted. So you would need to use sorted() anyway to sort it before each use or after each manipulation. The OrderedDict is therefore only slower and more memory intensive than an ordinary dictionary, while adding nothing you need.

OrderedDict are not for sorted dictionaries, but for dictionaries where the items have some sort of ordering that is not a sorting. Such as if you want to show things in the order they were added, or if you want you users to be able to order things arbitrarily.

Update: Further explanation

Why is OrderedDict not a solution? Because an OrderedDict is ordered not sorted.

Consider a standard dictionary:

>>> d = {'a': 0, 'b': 1, 'c': 2, 'd': 3, 'e': 4, 'f': 5}

It's not sorted, as we see below, 'c' will come before 'b'. It also has no order, if we add new things it appears what seems like random order:

>>> d['g'] = 6
>>> d['i'] = 8
>>> d
{'a': 0, 'c': 2, 'b': 1, 'e': 4, 'd': 3, 'g': 6, 'f': 5, 'i': 8}

OK, so let's use an OrderedDict then:

>>> o = OrderedDict(sorted({'a': 0, 'b': 1, 'c': 2, 'd': 3, 'e': 4, 'f': 5}.items()))
>>> o
OrderedDict([('a', 0), ('b', 1), ('c', 2), ('d', 3), ('e', 4), ('f', 5)])

Aha! Sorted! So OrderedDict works!? No.

>>> o['i'] = 8
>>> o['g'] = 6
>>> o
OrderedDict([('a', 0), ('b', 1), ('c', 2), ('d', 3), ('e', 4), ('f', 5), ('i', 8), ('g', 6)])

What? The g ended up after the i?!? Why!? Because the OrderedDict is not sorted, it's ordered. It remembers the order you add things. Not the sorting. This means that every time you use it you need to sort it first. An OrderedDict will only stay sorted as long as you don't add keys to it. But if you aren't going to modify it, then you don't need a dict. You can just as well have a list. Which is what you get from sorted():

>>> sorted(o.items())
[('a', 0), ('b', 1), ('c', 2), ('d', 3), ('e', 4), ('f', 5), ('g', 6), ('i', 8)]

But that works just as well with the standard dictionary, so the OrderedDictionary didn't help:

>>> sorted(d.items())
[('a', 0), ('b', 1), ('c', 2), ('d', 3), ('e', 4), ('f', 5), ('g', 6), ('i', 8)]

Conclusion So each time you want to loop over the dictionary in a sorted way, you need to do:

>>> for k in sorted(o):
...   print k, o[k]
... 
a 0
b 1
c 2
d 3
e 4
f 5
g 6
i 8

And that is no matter what dictionary you use. OrderedDict doesn't really help you, because it doesn't care about sorting, just the order you add things in.


It's worth noting that Python has a number of dictionary implementations that maintain the keys in sorted order. Consider the sortedcontainers module which is pure-Python and fast-as-C implementations. There's a performance comparison with other fast and feature-complete implementations benchmarked against one another.

For example:

>>> from sortedcontainers import SortedDict
>>> d = {'a': [1, 2, 3], 'c': ['one', 'two'], 'b': ['blah', 'bhasdf', 'asdf'], 'd': ['asdf', 'wer', 'asdf', 'zxcv']}
>>> s = SortedDict(**d)
>>> s.keys()
SortedSet(['a', 'b', 'c', 'd'])

You can also entirely replace your use of dict with SortedDict as it supports fast get/set operations and sorted iterations of items by key.


Here is a quick and easy function you can use to sort a dictionary by keys.

Put this code in a separate file called sdict.py:

def sortdict(dct):
    kys = dct.keys()
    kys.sort()
    from collections import OrderedDict
    d = OrderedDict()
    for x in kys: 
        for k, v in dct.iteritems():
            if (k == x):
                d[k] = v
    return d

Now, place this code into a separate file called test.py to test it with a sample dictionary:

from sdict import sortdict
import json
dct = {'sizes':[32,28,42], 'dog':'schnauser', 'cat':'siamese', 'bird':'falcon'}
dctx = sortdict(dct)
print json.dumps(dctx) 

And finally, call test.py from the command line:

$ python test.py
{"bird": "falcon", "cat": "siamese", "dog": "schnauser", "sizes": [32, 28, 42]}

I'm only using json.dumps line to show you that it's an actual dictionary, and not just a string representation. You can also test it with the type() function for that matter.

I included a nested list with numeric values in the sample dictionary to show that the function can handle more complex dictionaries, not just single-layer string-based dicts.

The code is pretty straightforward, so it would be easy to modify it to sort by values, if that's your preference - although sorting by value would not make sense if some of the values are objects, like lists, tuples or other dicts.

Admittedly, this only works in python 2.7 or later.

Cheers,
-=Cameron


As the other answer mentioned, the order of a dictionary's keys is arbitrary and you shouldn't rely on it.

If you're using Python 2.7 or 3.1 or later, try out collections.OrderedDict (2.7 docs; 3.1 docs; also see PEP 372). There's a link in the docs to a pure-Python version of OrderedDict that works on earlier Python versions.


It may also be worth mentioning the nlargest routine in heapq. This sorts and returns the top N items. Depending upon what is actually required, this may be handy if you play with the key parameter. I mainly mention this since I discovered it a couple of nights ago and it did exactly what I was after. See PEP 0265 and Heapq.


I will add my one cent to what others already explained. I happened to have the exact same problem in one specific case. I needed the output of my dictionary to always be the same for writing stable unit-tests.

If by chance it is what you are trying to achieve, or some other output related task, you don't have to sort anything at all, just use pprint module, among other features it will sort dictionaries by keys.

>>> d = {'a':1, 'b':2, 'c':3}
>>> print d
{'a': 1, 'c': 3, 'b': 2}

>>> from pprint import pprint
>>> pprint(d)
{'a': 1, 'b': 2, 'c': 3}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜