如何按照插入顺序从字典中检索项目?

68

能否按照插入顺序从Python字典中检索项目?


可能是为什么字典值不按插入顺序排序?的重复问题。 - nbro
2
这个问题(和过时的已接受答案)仍然是谷歌“按插入顺序排列的Python字典项”的#1结果。如果您正在阅读此内容,请为Brian 2018年的回答点赞。 - Rakurai
11个回答

71

如果你使用的是CPython 3.6+(或Python 3.7+的任何其他实现),标准Python dict默认会执行此操作。

在旧版Python中,您可以使用collections.OrderedDict来实现。


27
自 Python 3.7 起,标准字典会保留插入顺序。来自官方文档的说明:

自版本 3.7 起改变:字典顺序保证为插入顺序,这个行为是 CPython 在 3.6 中的实现细节。

因此,您可以正常遍历字典或使用 popitem() 方法。

2
让我们把这个答案点赞。此外,从文档中,第5.5节字典:“在字典上执行list(d)会返回一个列表,其中包含字典中使用的所有键,按插入顺序排序(如果您想要排序,只需使用sorted(d)即可)。 - Rakurai

20

使用OrderedDict(),自版本2.7起可用

只是出于好奇:

from collections import OrderedDict
a = {}
b = OrderedDict()
c = OrderedDict()

a['key1'] = 'value1'
a['key2'] = 'value2'

b['key1'] = 'value1'
b['key2'] = 'value2'

c['key2'] = 'value2'
c['key1'] = 'value1'

print a == b  # True
print a == c  # True
print b == c  # False

17

其他答案是正确的;这不可能,但你可以自己编写。但是,如果你不确定如何实际实现此类功能,请参考我刚刚编写和测试的完整可工作的实现,它是通过字典子类化实现的。(请注意,传递给构造函数的值的顺序是未定义的,但将先于后面传递的值,并且您始终可以不允许使用有序字典初始化值。)

class ordered_dict(dict):
    def __init__(self, *args, **kwargs):
        dict.__init__(self, *args, **kwargs)
        self._order = self.keys()

    def __setitem__(self, key, value):
        dict.__setitem__(self, key, value)
        if key in self._order:
            self._order.remove(key)
        self._order.append(key)

    def __delitem__(self, key):
        dict.__delitem__(self, key)
        self._order.remove(key)

    def order(self):
        return self._order[:]

    def ordered_items(self):
        return [(key,self[key]) for key in self._order]


od = ordered_dict()
od["hello"] = "world"
od["goodbye"] = "cruel world"
print od.order()            # prints ['hello', 'goodbye']

del od["hello"]
od["monty"] = "python"
print od.order()            # prints ['goodbye', 'monty']

od["hello"] = "kitty"
print od.order()            # prints ['goodbye', 'monty', 'hello']

print od.ordered_items()
# prints [('goodbye','cruel world'), ('monty','python'), ('hello','kitty')]

order_dict(('key_a', 'value_a'), ('key_b', 'value_b'))是否被正确排序?看起来__init__中的_order将被设置为self.keys(),这是按哈希顺序排序,而不是按输入顺序排序?只是好奇。 - Brian M. Hunt
你是正确的,这就是为什么我说:“传递给构造函数的值的顺序是未定义的,但会在稍后传递的值之前”。虽然可以将它们正确排序,但我不确定是否需要这样做,因为可以说这些对象是同时插入的。 - Eli Courtwright

5

使用基本的字典类无法做到这一点——它是按哈希值排序的。你可以构建自己的字典,实际上是一个键值对列表或类似的东西,这样就可以排序了。


2
你的字典实现可以使用标准字典和列表来代替,其中字典存储键值对关系,而列表则按照它们插入的顺序存储键。 - Binil Thomas

5
或者,将键作为元组,其中时间.now()作为元组中的第一个字段。
然后,你可以使用dictname.keys()检索键,进行排序,然后就完成了!
Gerry

6
如果不知道插入时间,就无法在字典中查找条目,这样就和键-值对列表没有区别了。 - user2357112

3

1

或者使用任何在PEP-372中描述的这里的实现,例如来自pythonutilsodict模块

我成功地使用了pocoo.org的实现,只需替换您的即可。

my_dict={}
my_dict["foo"]="bar"

使用

my_dict=odict.odict()
my_dict["foo"]="bar"

并且只需要这个文件


0

除非您将键存储在单独的列表中以供稍后引用,否则不可能实现。


-1

你可以通过插入表示输入顺序的键和值,然后在这些项上调用sorted()来完成排序。

>>> obj = {}
>>> obj[1] = 'Bob'
>>> obj[2] = 'Sally'
>>> obj[3] = 'Joe'
>>> for k, v in sorted(obj.items()):
...     print v
... 
Bob
Sally
Joe
>>> 

2
如果我们没有其他用途需要使用该密钥,我们会使用列表。这与列表所能做的一样,没有任何区别。 - user2357112
1
@user2357112,然而,这表达了另一种做OP所要求的事情的方法。OP没有问如何按插入顺序打印项目,OP说如何打印dict中的项目。这是很大的区别。 - A.J. Uppal
1
你已经改变了字典的格式,以至于它对原始目的没有用处。如果该字典最初是将姓名与电话号码关联起来的,那么你获得了一致的迭代顺序,但你不知道Bob的电话号码是多少。 - user2357112

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接