首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >切片Python OrderedDict

切片Python OrderedDict
EN

Stack Overflow用户
提问于 2015-06-22 08:34:46
回答 7查看 12.5K关注 0票数 25

在我的代码中,我经常需要从Python keys+values OrderedDict (来自collections包)获取一个子集范围的collections。切片不起作用(抛出TypeError: unhashable type),迭代的替代方法很麻烦:

代码语言:javascript
复制
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]

有更好的方法来完成这件事吗?

EN

回答 7

Stack Overflow用户

回答已采纳

发布于 2015-06-22 08:40:10

标准库中的有序dict不提供该功能。尽管库在collections.OrderedDict之前已经存在了几年,但它具有此功能(并且基本上提供了一个超集的OrderedDict):空隙有轨ruamel.ordereddict (我是后一个包的作者,它是在C中对odict的重新实现):

代码语言:javascript
复制
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):

代码语言:javascript
复制
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__细化。

代码语言:javascript
复制
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的较短版本来获得需要返回的实际切片:

代码语言:javascript
复制
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

代码语言:javascript
复制
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]
票数 17
EN

Stack Overflow用户

发布于 2015-06-22 08:44:08

您可以使用itertools.islice函数,它可以进行迭代并输出stop的第一个元素。这是有益的,因为迭代不支持常见的切片方法,而且您也不需要从items创建整个OrderedDict列表。

代码语言:javascript
复制
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)
票数 18
EN

Stack Overflow用户

发布于 2015-06-22 08:40:02

在Python 2中,您可以分割密钥。

代码语言:javascript
复制
x.keys()[1:3]

要同时支持Python 2和Python 3,首先要转换为一个列表:

代码语言:javascript
复制
list(k)[1:3]

Python2 OrderedDict.keys()实现正是这样做的。

在这两种情况下,您都会得到一个按正确顺序排列的键列表。如果首先创建一个完整的列表是一个问题,您可以使用itertools.islice()并将它生成的可迭代性转换为一个列表:

代码语言:javascript
复制
from itertools import islice

list(islice(x, 1, 3))

上述所有内容也可以应用于项目;使用Python2中的dict.viewitems()来获得与Python3 dict.items()提供的相同的迭代行为。在本例中,可以将islice()对象直接传递给另一个OrderedDict()

代码语言:javascript
复制
OrderedDict(islice(x.items(), 1, 3))  # x.viewitems() in Python 2
票数 7
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/30975339

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档