Ordered dicts

bearophileHUGS at lycos.com bearophileHUGS at lycos.com
Wed Sep 27 20:02:08 EDT 2006


Steve Holden:

I forgot a detail: in the Python version of Odict I use element
deletion is O(n). You need a second dict to improve that (or a duble
linked list of hashing operations, see below).

> FYI there was a *long* discussion around the need for Speed sprint about
> implementing ordered dicts. As the discussion started by your thread has
> started to reveal, everyone has just-ever-so-slightly-different
> requirements. IIRC the goal was dropped because it wasn't possible to
> agree on a specification.

I received a similar answer about graphs too. But this time I think the
semantic of an ordered dict is simple and clear enough, so I belive a
generally acceptable solution may be found still.
An implementation with double linked lists allows amortized O(1) for
all the usual dict metods, deletions too. Maybe firstkey()  lastkey()
methods can be added too, that return the first and last key of the
odict.
The following is a simple example, note that this is a "wrong"
implementation, because you can't scan the keys in the ordered way (you
can scan the values in a ordered way). I presume in a C implementation
you can find the key of a given value. If this isn't possibile without
creating a chain of hashing operations, then I too drop off from this
odict idea :-)

class Odict(dict):
  def __init__(self):
    dict.__init__(self)
    self.lh = None # list header
    self.lt = None # list tail

  def __getitem__(self, key):
    return dict.__getitem__(self, key)[1]

  def __setitem__(self, key, val):
    if key in self:
      dict.__getitem__(self, key)[1] = val
    else:
      new = [self.lt, val, None]
      dict.__setitem__(self, key, new)
      if self.lt: self.lt[2] = new
      self.lt = new
      if not self.lh: self.lh = new

  def __delitem__(self, k):
    if k in self:
      pred,_,succ= dict.__getitem__(self,k)
      if pred: pred[2] = succ
      else: self.lh = succ
      if succ: succ[0] = pred
      else: self.lt = pred
      dict.__delitem__(self, k)
    else: raise KeyError, k

Bye,
bearophile




More information about the Python-list mailing list