切片 Python OrderedDict [英] Slicing a Python OrderedDict
问题描述
在我的代码中,我经常需要从 Python OrderedDict
(来自 collections
包).切片不起作用(抛出 TypeError: unhashable type
),而迭代的替代方法很麻烦:
In my code I frequently need to take a subset range of keys+values from a Python OrderedDict
(from collections
package). Slicing doesn't work (throws TypeError: unhashable type
) and the alternative, iterating, is cumbersome:
from collections import OrderedDict
o = OrderedDict([('a', 1), ('b', 2), ('c', 3), ('d', 4)])
# want to do:
# x = o[1:3]
# need to do:
x = OrderedDict()
for idx, key in enumerate(o):
if 1 <= idx < 3:
x[key] = o[key]
有没有更好的方法来完成这项工作?
Is there a better way to get this done?
推荐答案
标准库中的有序 dict 不提供该功能.尽管在 collections.OrderedDict 之前已经存在了几年具有此功能的库(并且本质上提供了 OrderedDict 的超集):voidspace odict 和 ruamel.ordereddict(我是后一个包的作者,它是在 C 中重新实现的 odict):
The ordered dict in the standard library, doesn't provide that functionality. Even though libraries existed for a few years before collections.OrderedDict that have this functionality (and provide essentially a superset of OrderedDict): voidspace odict and ruamel.ordereddict (I am the author of the latter package, which is a reimplementation of odict in C):
from odict import OrderedDict as odict
p = odict([('a', 1), ('b', 2), ('c', 3), ('d', 4)])
print p[1:3]
在 ruamel.ordereddict 中,您可以放宽有序输入要求(AFAIK,如果键是有序的,您不能询问 dict 的派生词(这将是 ruamel.ordereddict 的良好补充,以识别 collection.OrderedDicts):
In ruamel.ordereddict you can relax the ordered input requirement (AFAIK you cannot ask derivative of dict if its keys are ordered (would be good addition to ruamel.ordereddict to recognise collection.OrderedDicts)):
from ruamel.ordereddict import ordereddict
q = ordereddict(o, relax=True)
print q[1:3]
r = odict([('a', 1), ('b', 2), ('c', 3), ('d', 4)])
print r[1:3]
如果你想(或不得不)留在标准库中,你可以将 collections.OrderedDict
的 __getitem__
子类化:
If you want (or have to) stay within the standard library you can sublass collections.OrderedDict
's __getitem__
:
class SlicableOrderedDict(OrderedDict):
def __getitem__(self, k):
if not isinstance(k, slice):
return OrderedDict.__getitem__(self, k)
x = SlicableOrderedDict()
for idx, key in enumerate(self.keys()):
if k.start <= idx < k.stop:
x[key] = self[key]
return x
s = SlicableOrderedDict([('a', 1), ('b', 2), ('c', 3), ('d', 4)])
print s[1:3]
当然,您可以使用 Martijn 或 Jimmy 的较短版本来获取需要返回的实际切片:
of course you could use Martijn's or Jimmy's shorter versions to get the actual slice that needs returning:
from itertools import islice
class SlicableOrderedDict(OrderedDict):
def __getitem__(self, k):
if not isinstance(k, slice):
return OrderedDict.__getitem__(self, k)
return SlicableOrderedDict(islice(self.viewitems(), k.start, k.stop))
t = SlicableOrderedDict([('a', 1), ('b', 2), ('c', 3), ('d', 4)])
print t[1:3]
或者如果你只是想在没有子类化的情况下改进所有现有的 OrderedDict
:
or if you just want smarten up all existing OrderedDict
s without subclassing:
def get_item(self, k):
if not isinstance(k, slice):
return OrderedDict._old__getitem__(self, k)
return OrderedDict(islice(self.viewitems(), k.start, k.stop))
OrderedDict._old__getitem__ = OrderedDict.__getitem__
OrderedDict.__getitem__ = get_item
u = OrderedDict([('a', 1), ('b', 2), ('c', 3), ('d', 4)])
print u[1:3]
这篇关于切片 Python OrderedDict的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!