16 ordereddictionary slice python-2.7
在我的代码中,我经常需要从Python OrderedDict(来自collections包)获取一系列键+值的子集.切片不起作用(抛出TypeError: unhashable type),替代,迭代,很麻烦:
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]
Run Code Online (Sandbox Code Playgroud)
有没有更好的方法来完成这项工作?
Ant*_*hon 14
标准库中的有序dict不提供该功能.尽管库在collections.OrderedDict之前存在了几年,它具有这种功能(并提供了一个基本上是OrderedDict的超集):voidspace odict和ruamel.ordereddict(我是后一个包的作者,这是在C中重新实现的odict ):
from odict import OrderedDict as odict
p = odict([('a', 1), ('b', 2), ('c', 3), ('d', 4)])
print p[1:3]
Run Code Online (Sandbox Code Playgroud)
在ruamel.ordereddict中,你可以放松有序的输入要求(AFAIK如果它的键是有序的,你不能要求dict的衍生物(对于识别collection.OrderedDicts是ruamel.ordereddict的良好补充)):
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]
Run Code Online (Sandbox Code Playgroud)
如果你想(或必须)标准库中留下来,你可以sublass collections.OrderedDict的__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]
Run Code Online (Sandbox Code Playgroud)
当然你可以使用Martijn或Jimmy的较短版本来获得需要返回的实际切片:
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]
Run Code Online (Sandbox Code Playgroud)
或者如果你只想OrderedDict在不进行子类化的情况下智能化所有现有的:
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]
Run Code Online (Sandbox Code Playgroud)
Jim*_*y C 14
您可以使用该itertools.islice函数,该函数采用iterable并输出第stop一个元素.这是有益的,因为iterables不支持常见的切片方法,您不需要items从OrderedDict 创建整个列表.
from collections import OrderedDict
from itertools import islice
o = OrderedDict([('a', 1), ('b', 2), ('c', 3), ('d', 4)])
sliced = islice(o.iteritems(), 3) # o.iteritems() is o.items() in Python 3
sliced_o = OrderedDict(sliced)
Run Code Online (Sandbox Code Playgroud)
在Python 2中,您可以对键进行切片:
x.keys()[1:3]
Run Code Online (Sandbox Code Playgroud)
要支持Python 2和Python 3,您首先要转换为列表:
list(k)[1:3]
Run Code Online (Sandbox Code Playgroud)
Python 2 OrderedDict.keys()实现正是如此.
在这两种情况下,您都会按正确顺序获得一系列密钥.如果首先创建整个列表是一个问题,您可以使用itertools.islice()它生成的迭代并将其转换为列表:
from itertools import islice
list(islice(x, 1, 3))
Run Code Online (Sandbox Code Playgroud)
以上所有也可以应用于物品; dict.viewitems()在Python 2中使用以获得与Python 3 dict.items()提供的相同的迭代行为.在这种情况下,您可以将islice()对象直接传递给另一个OrderedDict():
OrderedDict(islice(x.items(), 1, 3)) # x.viewitems() in Python 2
Run Code Online (Sandbox Code Playgroud)