简体   繁体   English

Python:字典中的元素顺序

[英]Python: Element order in dictionary

Here is my Django code that does not work as expected: 这是我的Django代码不能按预期工作:

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 ? 有没有办法保持原始元素顺序,所以帖子将在posts_to_return added

Thank you! 谢谢!

EDIT: Python 2.6, Django 1.3 编辑: Python 2.6,Django 1.3

Dicts in python (and most languages) have no order. python(和大多数语言)中的Dicts没有顺序。 You should instead use collections.OrderedDict . 您应该使用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. 如果添加顺序不是您要保留的顺序,也可以查看sorted()内置函数。

Use SortedDict instead of dict ( from django.utils.datastructures import SortedDict ) 使用SortedDict而不是dict( from django.utils.datastructures import SortedDict

SortedDict maintains it's order in it's keyOrder attribute. SortedDict在它的keyOrder属性中维护它的顺序。 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() 例如,要反转SortedDict的顺序,只需使用keyOrder.reverse()

post_list = SortedDict([(obj.id, obj) for obj in posts])
# reversing the post order in-place
post_list.keyOrder.reverse()

It's also worth noting that you can use one of Python's many dictionary implementations that maintains the keys in sorted order. 值得注意的是,您可以使用Python的许多字典实现之一,以按排序顺序维护密钥。 This is critical if you plan to do any insertions into your sorted dict. 如果您计划对已排序的dict进行任何插入,这一点至关重要。 Consider the sortedcontainers module which is pure-Python and fast-as-C implementations. 考虑sortedcontainers模块 ,它是纯Python和快速实现的C实现。 There's a SortedDict implementation that supports exactly what you need. 有一个SortedDict实现,可以完全支持您的需求。

>>> 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. 还有一个性能比较 ,它将几个流行的选项相互比较。

当您使用Django时,您可以使用SortedDictdocs

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. 因为还没有人引起人们的注意,我只会注意到OrderedDict文档表明这个配方是等效的,适用于Python 2.4及更高版本。 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. 你需要一个有序的字典,据我所知,它将在Python3.3中提供。 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. 您可以使用OrderedDict而不是Dict。

from collections import OrderedDict
...
post_list = OrderedDict([(obj.id, obj) for obj in posts])

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM