python中有序字典的有序字典

python中有序字典的有序字典,python,dictionary,Python,Dictionary,我需要一个存储字典的字典数据结构,如下所示: custom = {1: {'a': np.zeros(10), 'b': np.zeros(100)}, 2: {'c': np.zeros(20), 'd': np.zeros(200)}} 但问题是我在代码中多次迭代这个数据结构。每次迭代时,我都需要遵守迭代顺序,因为这个复杂数据结构中的所有元素都映射到一个1D数组(如果愿意,可以序列化),因此顺序很重要。为此,我考虑过编写一个有序的dict,但我不确定这是正确的解决方案

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

custom = {1: {'a': np.zeros(10), 'b': np.zeros(100)}, 
          2: {'c': np.zeros(20), 'd': np.zeros(200)}}
但问题是我在代码中多次迭代这个数据结构。每次迭代时,我都需要遵守迭代顺序,因为这个复杂数据结构中的所有元素都映射到一个1D数组(如果愿意,可以序列化),因此顺序很重要。为此,我考虑过编写一个有序的
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())

在这个有序结构中,我可以迭代任意次数,并且我实现了
\uuuuu call\uuuu
,因此我可以在较低的维度上迭代。我不喜欢这样的事实,如果列表中没有较低的维度,它不会给我任何错误。我还感到,每次调用
返回self[self.d][self.etype][self.idx-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)}
custom[1]['b']

当您首先对键进行排序时,可以在迭代时修复键的顺序:

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])

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

我认为使用
orderedict
s是最好的方法。它们是内置的,速度相对较快:

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
请注意,在Python 3.3+中,允许从生成
,可以消除
循环的最后一个

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\u over\u contents()
generator函数作为其
\uuu iter\uu()
方法,但这种方法可能会更慢,不允许表达式使用以下两种级别的索引:

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)}
custom[1]['b']

使用嵌套字典(或我的另一个答案中所示的
OrderedDefaultdicts)可以实现这一点。

这里有另一种选择,它使用OrderedDefaultdict来定义所需的树状数据结构。我在重复我的另一个定义

要使用它,您必须确保这些条目是按照您稍后要访问它们的顺序定义的

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()

我不能使用它,因为1可能存在,也可能不存在,0和2也是如此。啊,好的,所以您实际上需要外部
dict
中的键-没关系,抱歉误解了@aaragon我编辑了答案,以保留作为外部
dict
键的索引,并将所有不可用元素设置为
None
。您的解决方案仍然没有排序,例如,通过
custom[1]
循环可以获得
a
的元素,然后
b
,在不同的迭代中,元素
b
,然后
a
。这可以通过使用
OrderedDict
来解决,但是问题仍然存在:有没有更好的方法来处理这个问题?我在这个数据结构上迭代了很多次。这个结构在整个应用程序中迭代了很多次,我想做的是为k提供一个更为用户友好的方法来键入
,custom.items()中的v:对于枚举(v)中的i,r:#等
这似乎是一个完全不同的问题。的确,请看一看,但我必须仔细考虑这一点,因此我从选择正确的数据结构开始。感谢您的解决方案。如果您必须提供一个更友好的用户界面,以便按顺序遍历字典中的元素,那么有可能吗?假设我想在custom:中为el执行
,然后以有序的方式逐个遍历每个元素,你会怎么做?我的意思是,只使用一个循环,就可以按顺序遍历整个数据结构。我试图通过重写
\uu iter\uuu
\uu next\uuu
方法来实现这一点,但我失败得很惨。我还想问您是否可以解释一下您编写的代码,因为这对我来说是非常高级的Python。对于字典,
\uuuuu iter\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu,然而,基于字典的递归树结构可以支持多种形式的迭代——例如,宽度优先和深度优先遍历。此外,字典还有一个
items()
方法,它返回它所包含的所有
(键、值)
对的副本。由于这些差异,当您只说您希望按顺序遍历元素时,不清楚您试图实现什么。在这个上下文中,你认为什么是“元素”?我的答案中的代码是前