diccionario ordenado de diccionarios ordenados en python

Necesito una estructura de datos de diccionario que almacene diccionarios como se ve a continuación:

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

Pero el problema es que repito esta estructura de datos muchas veces en mi código. Cada vez que lo itero, necesito que se respete el orden de iteración porque todos los elementos de esta compleja estructura de datos se asignan a una matriz 1D (serializada si así lo desea), y por lo tanto el orden es importante. Pensé en escribir un dict ordenado de dict ordenado para esa materia, pero no estoy seguro de que esta sea la solución correcta, ya que parece que estoy eligiendo la estructura de datos incorrecta. ¿Cuál sería la solución más adecuada para mi caso?

ACTUALIZAR

Así que esto es lo que se me ocurrió hasta ahora:

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

Puedo iterar tantas veces como quiera en esta estructura ordenada, e implementé __call__ para poder iterar sobre las dimensiones inferiores. No me gusta el hecho de que si no hay una dimensión inferior presente en la lista, no me da ningún error. También tengo la sensación de que cada vez que llamo return self[self.d][self.etype][self.idx-1] es menos eficiente que la iteración original sobre el diccionario. ¿Es esto cierto? ¿Cómo puedo mejorar esto?

Aquí hay otra alternativa que utiliza un OrderedDefaultdict para definir la estructura de datos tipo árbol que desea. Estoy reutilizando la definición de eso de otra respuesta mía.

Para utilizarlo, debe asegurarse de que las entradas se definan en el orden en que desea acceder a ellas más adelante.

 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) 

No estoy seguro de entender su pregunta de seguimiento. Si la estructura de datos está limitada a dos niveles, podría usar nesteds for bucles para iterar sobre sus elementos en el orden en que se definieron. Por ejemplo:

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

(En Python 2, querría usar iteritems() lugar de items() .

Creo que usar OrderedDict s es la mejor manera. Están incorporados y son relativamente rápidos:

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

Si desea facilitar la iteración sobre el contenido de su estructura de datos, siempre puede proporcionar una función de utilidad para hacerlo:

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

Tenga en cuenta que en Python 3.3+, que permite el yield from , el último bucle for puede eliminarse:

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

Con uno de esos podrás escribir algo como:

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

Y ocultar la complejidad.

Si bien podría definir su propia clase en un bash de encapsular esta estructura de datos y usar algo como la función del generador iter_over_contents() como su __iter__() , ese enfoque probablemente sería más lento y no permitiría expresiones que usen dos niveles de indexación. esto siguiente:

 custom[1]['b'] 

el uso de diccionarios nesteds (o OrderedDefaultdict s como se muestra en mi otra respuesta) haría.

¿Podrías usar una lista de diccionarios?

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

Esto podría funcionar si el diccionario externo es el único que necesita en el orden correcto. Puede seguir accediendo a los diccionarios internos con custom[0] o custom[1] (con cuidado, la indexación ahora comienza en 0 ).

Si no se utilizan todos los índices, podría hacer lo siguiente:

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

Puede arreglar el orden de sus claves mientras itera cuando las ordena:

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

Si desea reducir sorted() llamadas sorted() , es posible que desee almacenar las claves en una lista adicional que luego servirá como su orden de iteración:

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

Debería estar preparado para realizar tantas iteraciones sobre su estructura de datos como necesite.