切片Python OrderedDict

时间:2015-06-22 08:34:46

标签: python-2.7 slice ordereddictionary

在我的代码中,我经常需要从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]

有没有更好的方法来完成这项工作?

7 个答案:

答案 0 :(得分:12)

标准库中的有序字典不提供该功能。即使库在collections.OrderedDict之前存在了几年,它们具有此功能(并且基本上提供了OrderedDict的超集):voidspace odictruamel.ordereddict(我是后一个包的作者,这是一个在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)):

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]

答案 1 :(得分:12)

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

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)

答案 2 :(得分:5)

在Python 2中,您可以切片

x.keys()[1:3]

并且为了支持Python 2和Python 3,您首先要转换为列表:

list(k)[1:3]

Python 2 OrderedDict.keys()实现完全正确。

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

from itertools import islice

list(islice(x, 1, 3))

以上所有也可以应用于物品;在Python 2中使用dict.viewitems()来获得与Python 3 dict.items()提供的相同的迭代行为。在这种情况下,您可以将islice()对象直接传递给另一个OrderedDict()

OrderedDict(islice(x.items(), 1, 3))  # x.viewitems() in Python 2

答案 3 :(得分:0)

我想使用密钥进行切片,因为我事先并不知道索引:

o = OrderedDict(zip(list('abcdefghijklmnopqrstuvwxyz'),range(1,27)))

stop = o.keys().index('e')           # -> 4
OrderedDict(islice(o.items(),stop))  # -> OrderedDict([('a', 1), ('b', 2), ('c', 3)])

或从start切换到stop

start = o.keys().index('c')                    # -> 2
stop = o.keys().index('e')                     # -> 4
OrderedDict(islice(o.iteritems(),start,stop))  # -> OrderedDict([('c', 3), ('d', 4)])

答案 4 :(得分:0)

def slice_odict(odict, start=None, end=None):
    return OrderedDict([
        (k,v) for (k,v) in odict.items() 
        if k in list(odict.keys())[start:end]
    ])

这允许:

>>> x = OrderedDict([('a',1), ('b',2), ('c',3), ('d',4)])
>>> slice_odict(x, start=-1)
OrderedDict([('d', 4)])
>>> slice_odict(x, end=-1)
OrderedDict([('a', 1), ('b', 2), ('c', 3)])
>>> slice_odict(x, start=1, end=3)
OrderedDict([('b', 2), ('c', 3)])

答案 5 :(得分:0)

我能够使用以下方法对 OrderedDict 进行切片:

list(myordereddict.values())[start:stop]

我没有测试性能。

答案 6 :(得分:-1)

您正在处理双端队列或双端队列,这是经典的数据结构。这是链接:https://www.geeksforgeeks.org/deque-in-python/