python中有序字典的有序字典

时间:2015-12-15 16:30:51

标签: python dictionary

我需要一个存储字典的字典数据结构,如下所示:

custom = {1: {'a': np.zeros(10), 'b': np.zeros(100)}, 
          2: {'c': np.zeros(20), 'd': np.zeros(200)}}

但问题是我在代码中多次迭代这个数据结构。每次迭代它时,我都需要遵守迭代的顺序,因为这个复杂数据结构中的所有元素都映射到一维数组(如果你愿意,可以序列化),因此顺序很重要。我考虑过写一个有序dict的有序dict,但我不确定这是否是正确的解决方案,因为我似乎选择了错误的数据结构。对我的案子来说,最合适的解决办法是什么?

更新

所以这就是我到目前为止所提出的:

class Test(list):

    def __init__(self, *args, **kwargs):

        super(Test, self).__init__(*args, **kwargs)

        for k,v in args[0].items():
            self[k] = OrderedDict(v)

        self.d = -1
        self.iterator = iter(self[-1].keys())
        self.etype = next(self.iterator)
        self.idx = 0


    def __iter__(self):
        return self

    def __next__(self):

        try:
            self.idx += 1
            return self[self.d][self.etype][self.idx-1]

        except IndexError:

            self.etype = next(self.iterator)
            self.idx = 0
            return self[self.d][self.etype][self.idx-1]

    def __call__(self, d):

        self.d = -1 - d
        self.iterator = iter(self[self.d].keys())
        self.etype = next(self.iterator)
        self.idx = 0
        return self


def main(argv=()):

    tst = Test(elements)
    for el in tst:
        print(el)
    # loop over a lower dimension
    for el in tst(-2):
        print(el)

    print(tst)


    return 0

if __name__ == "__main__":
    sys.exit(main())

我可以在这个有序的结构中迭代多次,我实现了__call__,所以我可以遍历较低的维度。我不喜欢这样的事实:如果列表中没有较低的维度,它不会给我任何错误。我也有这种感觉,每次调用return self[self.d][self.etype][self.idx-1]都不如字典上的原始迭代效率低。这是真的?我怎样才能改善这个?

4 个答案:

答案 0 :(得分:2)

我认为使用OrderedDict是最好的方法。它们是内置且相对较快的:

custom = OrderedDict([(1, OrderedDict([('a', np.zeros(10)),
                                       ('b', np.zeros(100))])),
                      (2, OrderedDict([('c', np.zeros(20)),
                                       ('d', np.zeros(200))]))])

如果您想轻松迭代数据结构的内容,您可以随时提供实用程序功能:

def iter_over_contents(data_structure):
    for delem in data_structure.values():
        for v in delem.values():
            for row in v:
                yield row

请注意,在允许yield from <expression>的Python 3.3+中,可以消除最后一个for循环:

def iter_over_contents(data_structure):
    for delem in data_structure.values():
        for v in delem.values():
            yield from v

有了其中一个,你就可以写下这样的东西:

for elem in iter_over_contents(custom):
    print(elem)

并隐藏复杂性。

虽然可以定义您自己的类,以尝试封装此数据结构并使用类似iter_over_contents()生成器函数的方法作为其__iter__()方法,但这种方法很可能更慢,不会允许使用两级索引的表达式,如下所示:

custom[1]['b']

使用嵌套字典(或OrderedDefaultdict s,如我的其他答案所示)。

答案 1 :(得分:2)

这是另一种使用OrderedDefaultdict定义所需树状数据结构的替代方法。我正在重复使用我的另一个answer中的定义。

要使用它,您必须确保在以后按照您想要访问它们的顺序定义条目。

class OrderedDefaultdict(OrderedDict):
    def __init__(self, *args, **kwargs):
        if not args:
            self.default_factory = None
        else:
            if not (args[0] is None or callable(args[0])):
                raise TypeError('first argument must be callable or None')
            self.default_factory = args[0]
            args = args[1:]
        super(OrderedDefaultdict, self).__init__(*args, **kwargs)

    def __missing__ (self, key):
        if self.default_factory is None:
            raise KeyError(key)
        self[key] = default = self.default_factory()
        return default

    def __reduce__(self):  # optional, for pickle support
        args = (self.default_factory,) if self.default_factory else ()
        return self.__class__, args, None, None, self.iteritems()

Tree = lambda: OrderedDefaultdict(Tree)

custom = Tree()
custom[1]['a'] = np.zeros(10)
custom[1]['b'] = np.zeros(100)
custom[2]['c'] = np.zeros(20)
custom[2]['d'] = np.zeros(200)

我不确定我理解你的后续问题。如果数据结构限制为两个级别,则可以使用嵌套的for循环按其定义的顺序迭代其元素。例如:

for key1, subtree in custom.items():
    for key2, elem in subtree.items():
        print('custom[{!r}][{!r}]: {}'.format(key1, key2, elem))

(在Python 2中,您希望使用iteritems()代替items()。)

答案 2 :(得分:1)

你能用一个字典列表吗?

custom = [{'a': np.zeros(10), 'b': np.zeros(100)},
          {'c': np.zeros(20), 'd': np.zeros(200)}]

如果外部字典是您按正确顺序需要的唯一字典,则可以使用。您仍然可以使用custom[0]custom[1]访问内部词典(请注意,索引现在从0开始)。

如果未使用所有索引,则可以执行以下操作:

custom = [None] * maxLength   # maximum dict size you expect

custom[1] = {'a': np.zeros(10), 'b': np.zeros(100)}
custom[2] = {'c': np.zeros(20), 'd': np.zeros(200)}

答案 3 :(得分:0)

您可以在重复排序时修复键的顺序:

for key in sorted(custom.keys()):
    print(key, custom[key])

如果要减少sorted() - 调用,您可能希望将密钥存储在一个额外的列表中,该列表将作为您的迭代顺序:

ordered_keys = sorted(custom.keys())
for key in ordered_keys:
    print(key, custom[key])

您应该准备好根据需要对数据结构进行尽可能多的迭代。