Python: Element order in dictionary
Here is my Django code that does not 开发者_如何转开发work as expected:
posts = Post.objects.all().order_by('-added')[:20] # ordered by 'added'
post_list = dict([(obj.id, obj) for obj in posts])
# ... some operations with dictionary elements go here ...
posts_to_return = [post for post_id, post in post_list.items()] # order by 'id' now!
Is there a way to keep the original element order, so the posts would be ordered by added
in posts_to_return
?
Thank you!
EDIT: Python 2.6, Django 1.3
Use SortedDict instead of dict (from django.utils.datastructures import SortedDict
)
SortedDict maintains it's order in it's keyOrder
attribute. So you can manipulate the ordering without reconstructing dict if you want to. For example, to reverse the SortedDict's order just use keyOrder.reverse()
post_list = SortedDict([(obj.id, obj) for obj in posts])
# reversing the post order in-place
post_list.keyOrder.reverse()
Dicts in python (and most languages) have no order. You should instead use collections.OrderedDict
. This will retain the order of items as they are added. You can also look at the sorted()
builtin if the order of addition isn't the order you're trying to preserve.
It's also worth noting that you can use one of Python's many dictionary implementations that maintains the keys in sorted order. This is critical if you plan to do any insertions into your sorted dict. Consider the sortedcontainers module which is pure-Python and fast-as-C implementations. There's a SortedDict implementation that supports exactly what you need.
>>> from sortedcontainers import SortedDict
>>> posts = Post.objects.all().order_by('-added')[:20] # ordered by 'added'
>>> post_list = SortedDict([(obj.id, obj) for obj in posts])
>>> # ... some operations with dictionary elements go here ...
>>> # This is now automatically ordered by id:
>>> posts_to_return = [post for post_id, post in post_list.items()]
There's also a performance comparison that benchmarks several popular options against one another.
As you are using Django you could use SortedDict
(docs)
Because no one has drawn attention to it yet, I'll simply note that the OrderedDict docs indicate that this recipe is equivalent and works on Python 2.4 and up. So at least you don't have to roll your own.
You would need an ordered dictionary, which will be available in Python3.3 as far as I know. So you will probably have to order your result "by hand". Depending on your operations (which you havn't shown) it might be possible to just reuse the original posts list. But without knowing the operations, I can only guess.
You can use an OrderedDict instead of a Dict.
from collections import OrderedDict
...
post_list = OrderedDict([(obj.id, obj) for obj in posts])
精彩评论