字典和 OrderedDict 的区别
Difference between dictionary and OrderedDict
我正在尝试获取已排序的字典。但是 mydict
和 orddict
之间的项目顺序似乎没有改变。
from collections import OrderedDict
mydict = {'a': 1, 'b': 2, 'c': 3, 'd': 4}
orddict = OrderedDict(mydict)
print(mydict, orddict)
# print items in mydict:
print('mydict')
for k, v in mydict.items():
print(k, v)
print('ordereddict')
# print items in ordered dictionary
for k, v in orddict.items():
print(k, v)
# print the dictionary keys
# for key in mydict.keys():
# print(key)
# print the dictionary values
# for value in mydict.values():
# print(value)
OrderedDict
保留元素插入的顺序:
>>> od = OrderedDict()
>>> od['c'] = 1
>>> od['b'] = 2
>>> od['a'] = 3
>>> od.items()
[('c', 1), ('b', 2), ('a', 3)]
>>> d = {}
>>> d['c'] = 1
>>> d['b'] = 2
>>> d['a'] = 3
>>> d.items()
[('a', 3), ('c', 1), ('b', 2)]
所以 OrderedDict
不会为您 排序 元素,它 保留 您给它的顺序。
如果你想要"sort"一本字典,你可能想要
>>> sorted(d.items())
[('a', 1), ('b', 2), ('c', 3)]
Ordered dictionaries are just like regular dictionaries but they remember the order that items were inserted. When iterating over an ordered dictionary, the items are returned in the order their keys were first added.
所以它只按照添加到dict中的顺序排序
您可以通过以下方式按键构建OrderedDict订单,
orddict = OrderedDict(sorted(mydict.items(), key = lambda t: t[0]))
或者就像@ShadowRanger 在评论中提到的那样
orddict = OrderedDict(sorted(d.items()))
如果要按值排序,
orddict = OrderedDict(sorted(mydict.items(), key = lambda t: t[1]))
加上 Brian 的回答,OrderedDict
真的很棒。原因如下:
您可以将它用作简单的 dict
对象,因为它支持与其他 Mapping
对象(例如 collections.counter.
[=28)进行相等性测试=]
OrderedDict
保留了 Brian 解释的插入顺序。除此之外,它还有一个方法 popitem,其中 returns (key,value) 以 LIFO 顺序配对。因此,您也可以将其用作映射 'stack'.
您不仅可以获得 dict
的全部功能,还可以获得一些很酷的技巧。
自 Python 3.7 起,对 dict
built-in 的新改进是:
the insertion-order preservation nature of dict objects has been declared to be an official part of the Python language spec.
这意味着不再需要 OrderedDict
。他们几乎是一样的。
需要考虑的一些小细节...
以下是 Python 3.7+ dict
和 OrderedDict
之间的一些比较:
from collections import OrderedDict
d = {'b': 1, 'a': 2}
od = OrderedDict([('b', 1), ('a', 2)])
# they are equal with content and order
assert d == od
assert list(d.items()) == list(od.items())
assert repr(dict(od)) == repr(d)
显然,这两个对象的字符串表示形式存在差异,dict
对象的形式更自然、更紧凑。
str(d) # {'b': 1, 'a': 2}
str(od) # OrderedDict([('b', 1), ('a', 2)])
至于两者的方法不同,这个问题可以用集合论来回答:
d_set = set(dir(d))
od_set = set(dir(od))
od_set.difference(d_set)
# {'__dict__', '__reversed__', 'move_to_end'} for Python 3.7
# {'__dict__', 'move_to_end'} for Python 3.8+
这意味着 OrderedDict
最多有两个 dict
没有 built-in 的特征,但是 work-arounds 显示在这里:
__reversed__
/ reversed()
的解决方法
Python 3.8+、which fixed this issue 确实不需要解决方法。 OrderedDict
可以“反转”,它只是反转键(不是整个字典):
reversed(od) # <odict_iterator at 0x7fc03f119888>
list(reversed(od)) # ['a', 'b']
# with Python 3.7:
reversed(d) # TypeError: 'dict' object is not reversible
list(reversed(list(d.keys()))) # ['a', 'b']
# with Python 3.8+:
reversed(d) # <dict_reversekeyiterator at 0x16caf9d2a90>
list(reversed(d)) # ['a', 'b']
使用 Python 3.7+:
正确反转整个字典
dict(reversed(list(d.items()))) # {'a': 2, 'b': 1}
move_to_end
的解决方法
OrderedDict
有一个move_to_end
方法,实现起来很简单:
od.move_to_end('b') # now it is: OrderedDict([('a', 2), ('b', 1)])
d['b'] = d.pop('b') # now it is: {'a': 2, 'b': 1}
从 CPython 3.6 开始,所有其他 Python 实现从 Python 3.7 开始,内置的 dict
已排序 - 您按照插入的顺序取出物品。这使得 dict
和 OrderedDict
实际上相同。
The documentation for OrderedDict
列出了剩余的差异。最重要的是
OrderedDict
的相等运算检查匹配顺序。
还有一些小的实际差异:
dict.popitem()
takes no arguments, whereas OrderedDict.popitem(last=True)
接受一个可选的 last=
参数,让您弹出第一项而不是最后一项。
OrderedDict
有一个 move_to_end(key, last=True)
方法可以有效地将元素重新定位到末尾或开头。使用 dict
s,您可以通过重新插入键将其移动到末尾:mydict['key'] = mydict.pop('key')
- 直到 Python 3.8,你可以做
reversed(OrderedDict())
但 reversed({})
会引发 TypeError: 'dict' object is not reversible
错误,因为他们忘记添加 __reversed__
dunder 方法dict
他们下单的时候。现在已修复。
还有一些底层差异可能意味着您可以通过 OrderedDict
:
为某些特定用例获得更好的性能
- 常规
dict
被设计为非常擅长映射
操作。跟踪广告顺序是次要的。
-
OrderedDict
被设计为擅长重新排序操作。
Space效率、迭代速度、更新性能
操作是次要的。
- 算法上,
OrderedDict
可以处理频繁的重新排序
操作优于 dict
。这使其适合跟踪
最近访问(例如 LRU cache)。
请参阅此 great talk from 2016 by Raymond Hettinger 了解有关 Python 词典如何实现的详细信息。
我正在尝试获取已排序的字典。但是 mydict
和 orddict
之间的项目顺序似乎没有改变。
from collections import OrderedDict
mydict = {'a': 1, 'b': 2, 'c': 3, 'd': 4}
orddict = OrderedDict(mydict)
print(mydict, orddict)
# print items in mydict:
print('mydict')
for k, v in mydict.items():
print(k, v)
print('ordereddict')
# print items in ordered dictionary
for k, v in orddict.items():
print(k, v)
# print the dictionary keys
# for key in mydict.keys():
# print(key)
# print the dictionary values
# for value in mydict.values():
# print(value)
OrderedDict
保留元素插入的顺序:
>>> od = OrderedDict()
>>> od['c'] = 1
>>> od['b'] = 2
>>> od['a'] = 3
>>> od.items()
[('c', 1), ('b', 2), ('a', 3)]
>>> d = {}
>>> d['c'] = 1
>>> d['b'] = 2
>>> d['a'] = 3
>>> d.items()
[('a', 3), ('c', 1), ('b', 2)]
所以 OrderedDict
不会为您 排序 元素,它 保留 您给它的顺序。
如果你想要"sort"一本字典,你可能想要
>>> sorted(d.items())
[('a', 1), ('b', 2), ('c', 3)]
Ordered dictionaries are just like regular dictionaries but they remember the order that items were inserted. When iterating over an ordered dictionary, the items are returned in the order their keys were first added.
所以它只按照添加到dict中的顺序排序
您可以通过以下方式按键构建OrderedDict订单,
orddict = OrderedDict(sorted(mydict.items(), key = lambda t: t[0]))
或者就像@ShadowRanger 在评论中提到的那样
orddict = OrderedDict(sorted(d.items()))
如果要按值排序,
orddict = OrderedDict(sorted(mydict.items(), key = lambda t: t[1]))
加上 Brian 的回答,OrderedDict
真的很棒。原因如下:
您可以将它用作简单的
[=28)进行相等性测试=]dict
对象,因为它支持与其他Mapping
对象(例如 collections.counter.OrderedDict
保留了 Brian 解释的插入顺序。除此之外,它还有一个方法 popitem,其中 returns (key,value) 以 LIFO 顺序配对。因此,您也可以将其用作映射 'stack'.
您不仅可以获得 dict
的全部功能,还可以获得一些很酷的技巧。
自 Python 3.7 起,对 dict
built-in 的新改进是:
the insertion-order preservation nature of dict objects has been declared to be an official part of the Python language spec.
这意味着不再需要 OrderedDict
。他们几乎是一样的。
需要考虑的一些小细节...
以下是 Python 3.7+ dict
和 OrderedDict
之间的一些比较:
from collections import OrderedDict
d = {'b': 1, 'a': 2}
od = OrderedDict([('b', 1), ('a', 2)])
# they are equal with content and order
assert d == od
assert list(d.items()) == list(od.items())
assert repr(dict(od)) == repr(d)
显然,这两个对象的字符串表示形式存在差异,dict
对象的形式更自然、更紧凑。
str(d) # {'b': 1, 'a': 2}
str(od) # OrderedDict([('b', 1), ('a', 2)])
至于两者的方法不同,这个问题可以用集合论来回答:
d_set = set(dir(d))
od_set = set(dir(od))
od_set.difference(d_set)
# {'__dict__', '__reversed__', 'move_to_end'} for Python 3.7
# {'__dict__', 'move_to_end'} for Python 3.8+
这意味着 OrderedDict
最多有两个 dict
没有 built-in 的特征,但是 work-arounds 显示在这里:
__reversed__
/ reversed()
的解决方法
Python 3.8+、which fixed this issue 确实不需要解决方法。 OrderedDict
可以“反转”,它只是反转键(不是整个字典):
reversed(od) # <odict_iterator at 0x7fc03f119888>
list(reversed(od)) # ['a', 'b']
# with Python 3.7:
reversed(d) # TypeError: 'dict' object is not reversible
list(reversed(list(d.keys()))) # ['a', 'b']
# with Python 3.8+:
reversed(d) # <dict_reversekeyiterator at 0x16caf9d2a90>
list(reversed(d)) # ['a', 'b']
使用 Python 3.7+:
正确反转整个字典dict(reversed(list(d.items()))) # {'a': 2, 'b': 1}
move_to_end
的解决方法
OrderedDict
有一个move_to_end
方法,实现起来很简单:
od.move_to_end('b') # now it is: OrderedDict([('a', 2), ('b', 1)])
d['b'] = d.pop('b') # now it is: {'a': 2, 'b': 1}
从 CPython 3.6 开始,所有其他 Python 实现从 Python 3.7 开始,内置的 dict
已排序 - 您按照插入的顺序取出物品。这使得 dict
和 OrderedDict
实际上相同。
The documentation for OrderedDict
列出了剩余的差异。最重要的是
OrderedDict
的相等运算检查匹配顺序。
还有一些小的实际差异:
dict.popitem()
takes no arguments, whereasOrderedDict.popitem(last=True)
接受一个可选的last=
参数,让您弹出第一项而不是最后一项。OrderedDict
有一个move_to_end(key, last=True)
方法可以有效地将元素重新定位到末尾或开头。使用dict
s,您可以通过重新插入键将其移动到末尾:mydict['key'] = mydict.pop('key')
- 直到 Python 3.8,你可以做
reversed(OrderedDict())
但reversed({})
会引发TypeError: 'dict' object is not reversible
错误,因为他们忘记添加__reversed__
dunder 方法dict
他们下单的时候。现在已修复。
还有一些底层差异可能意味着您可以通过 OrderedDict
:
- 常规
dict
被设计为非常擅长映射 操作。跟踪广告顺序是次要的。 -
OrderedDict
被设计为擅长重新排序操作。 Space效率、迭代速度、更新性能 操作是次要的。 - 算法上,
OrderedDict
可以处理频繁的重新排序 操作优于dict
。这使其适合跟踪 最近访问(例如 LRU cache)。
请参阅此 great talk from 2016 by Raymond Hettinger 了解有关 Python 词典如何实现的详细信息。