ordered dictionary of ordered dictionaries in python

  • Last Update :
  • Techknowledgy :

An OrderedDict is a dictionary subclass that remembers the order that keys were first inserted. The only difference between dict() and OrderedDict() is that:,OrderedDict preserves the order in which the keys are inserted. A regular dict doesn’t track the insertion order and iterating it gives the values in an arbitrary order. By contrast, the order the items are inserted is remembered by OrderedDict.,Ordered dict in Python version 2.7 consumes more memory than normal dict. This is due to the underlying Doubly Linked List implementation for keeping the order. In Python 2.7 Ordered Dict is not dict subclass, it’s a specialized container from collections module.,2. Deletion and Re-Inserting: Deleting and re-inserting the same key will push it to the back as OrderedDict, however, maintains the order of insertion.

Output: 

This is a Dict:
   a 1
c 3
b 2
d 4

This is an Ordered Dict:
   a 1
b 2
c 3
d 4

Suggestion : 2

To make use of it, you have to ensure the entries are defined in the order you want to access them in later on.

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)

I'm not sure I understand your follow-on question. If the data structure is limited to two levels, you could use nested for loops to iterate over its elements in the order they were defined. For example:

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

I think using OrderedDicts is the best way. They're built-in and relatively fast:

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

If you want to make it easy to iterate over the contents of the your data structure, you can always provide a utility function to do so:

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

Note that in Python 3.3+, which allows yield from <expression>, the last for loop can be eliminated:

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

While you could define your own class in an attempt to encapsulate this data structure and use something like the iter_over_contents() generator function as its __iter__() method, that approach would likely be slower and wouldn't allow expressions using two levels of indexing such this following:

custom[1]['b']

Could you just use a list of dictionaries?

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

If not all of the indices are used, you could do the following:

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

You can fix the order of your keys while iterating when you sort them first:

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

If you want to reduce sorted()-calls, you may want to store the keys in an extra list which will then serve as your iteration order:

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

Suggestion : 3

Ordered dictionaries are just like regular dictionaries but have some extra capabilities relating to ordering operations. They have become less important now that the built-in dict class gained the ability to remember insertion order (this new behavior became guaranteed in Python 3.7).,The regular dict was designed to be very good at mapping operations. Tracking insertion order was secondary.,The OrderedDict algorithm can handle frequent reordering operations better than dict. As shown in the recipes below, this makes it suitable for implementing various kinds of LRU caches.,In addition to the usual mapping methods, ordered dictionaries also support reverse iteration using reversed().

>>> baseline = {
      'music': 'bach',
      'art': 'rembrandt'
   } >>>
   adjustments = {
      'art': 'van gogh',
      'opera': 'carmen'
   } >>>
   list(ChainMap(adjustments, baseline))['music', 'art', 'opera']
>>> combined = baseline.copy() >>>
   combined.update(adjustments) >>>
   list(combined)['music', 'art', 'opera']
import builtins
pylookup = ChainMap(locals(), globals(), vars(builtins))
import os, argparse

defaults = {
   'color': 'red',
   'user': 'guest'
}

parser = argparse.ArgumentParser()
parser.add_argument('-u', '--user')
parser.add_argument('-c', '--color')
namespace = parser.parse_args()
command_line_args = {
   k: v
   for k,
   v in vars(namespace).items() if v is not None
}

combined = ChainMap(command_line_args, os.environ, defaults)
print(combined['color'])
print(combined['user'])
c = ChainMap() # Create root context
d = c.new_child() # Create nested child context
e = c.new_child() # Child of c, independent from d
e.maps[0] # Current context dictionary--like Python 's locals()
e.maps[-1] # Root context--like Python 's globals()
e.parents # Enclosing context chain--like Python 's nonlocals

d['x'] = 1 # Set value in current context
d['x'] # Get first key in the chain of contexts
del d['x'] # Delete from current context
list(d) # All nested values
k in d # Check all nested values
len(d) # Number of nested values
d.items() # All nested items
dict(d) # Flatten into a regular dictionary
class DeepChainMap(ChainMap):
   'Variant of ChainMap that allows direct updates to inner scopes'

def __setitem__(self, key, value):
   for mapping in self.maps:
   if key in mapping:
   mapping[key] = value
return
self.maps[0][key] = value

def __delitem__(self, key):
   for mapping in self.maps:
   if key in mapping:
   del mapping[key]
return
raise KeyError(key)

   >>>
   d = DeepChainMap({
      'zebra': 'black'
   }, {
      'elephant': 'blue'
   }, {
      'lion': 'yellow'
   }) >>>
   d['lion'] = 'orange'
# update an existing key two levels down
   >>>
   d['snake'] = 'red'
# new keys get added to the topmost dict
   >>>
   del d['elephant'] # remove an existing key one level down >>>
   d # display result
DeepChainMap({
   'zebra': 'black',
   'snake': 'red'
}, {}, {
   'lion': 'orange'
})