在我的代码中,我经常需要从Python keys+values OrderedDict (来自collections包)获取一个子集范围的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]有更好的方法来完成这件事吗?
发布于 2015-06-22 08:40:10
标准库中的有序dict不提供该功能。尽管库在collections.OrderedDict之前已经存在了几年,但它具有此功能(并且基本上提供了一个超集的OrderedDict):空隙有轨和ruamel.ordereddict (我是后一个包的作者,它是在C中对odict的重新实现):
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):
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__细化。
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的较短版本来获得需要返回的实际切片:
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:
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]发布于 2015-06-22 08:44:08
您可以使用itertools.islice函数,它可以进行迭代并输出stop的第一个元素。这是有益的,因为迭代不支持常见的切片方法,而且您也不需要从items创建整个OrderedDict列表。
from collections import OrderedDict
from itertools import islice
o = OrderedDict([('a', 1), ('b', 2), ('c', 3), ('d', 4)])
sliced = islice(o.items(), 3) # o.iteritems() in Python 2.7 is o.items() in Python 3
sliced_o = OrderedDict(sliced)发布于 2015-06-22 08:40:02
在Python 2中,您可以分割密钥。
x.keys()[1:3]要同时支持Python 2和Python 3,首先要转换为一个列表:
list(k)[1:3]Python2 OrderedDict.keys()实现正是这样做的。
在这两种情况下,您都会得到一个按正确顺序排列的键列表。如果首先创建一个完整的列表是一个问题,您可以使用itertools.islice()并将它生成的可迭代性转换为一个列表:
from itertools import islice
list(islice(x, 1, 3))上述所有内容也可以应用于项目;使用Python2中的dict.viewitems()来获得与Python3 dict.items()提供的相同的迭代行为。在本例中,可以将islice()对象直接传递给另一个OrderedDict():
OrderedDict(islice(x.items(), 1, 3)) # x.viewitems() in Python 2https://stackoverflow.com/questions/30975339
复制相似问题