|
|
 |
|
Title: Ordered Dictionary
Submitter: David Benjamin
(other recipes)
Last Updated: 2002/01/21
Version no: 1.2
Category:
Extending
|
|
5 vote(s)
|
|
|
|
Description:
This dictionary class extends UserDict to record the order in which items are added. Calling keys(), values(), items(), etc. will return results in this order. This works similarly to the array type in PHP.
Source: Text Source
from UserDict import UserDict
class odict(UserDict):
def __init__(self, dict = None):
self._keys = []
UserDict.__init__(self, dict)
def __delitem__(self, key):
UserDict.__delitem__(self, key)
self._keys.remove(key)
def __setitem__(self, key, item):
UserDict.__setitem__(self, key, item)
if key not in self._keys: self._keys.append(key)
def clear(self):
UserDict.clear(self)
self._keys = []
def copy(self):
dict = UserDict.copy(self)
dict._keys = self._keys[:]
return dict
def items(self):
return zip(self._keys, self.values())
def keys(self):
return self._keys
def popitem(self):
try:
key = self._keys[-1]
except IndexError:
raise KeyError('dictionary is empty')
val = self[key]
del self[key]
return (key, val)
def setdefault(self, key, failobj = None):
UserDict.setdefault(self, key, failobj)
if key not in self._keys: self._keys.append(key)
def update(self, dict):
UserDict.update(self, dict)
for key in dict.keys():
if key not in self._keys: self._keys.append(key)
def values(self):
return map(self.get, self._keys)
Discussion:
Often it is useful to use a dictionary to store information where the order of that information matters. In Python, one must usually keep a list of keys and pass the list along with the dictionary to any functions that need to maintain this order. This implementation stores the list of keys internally and overrides the usual accessor methods to keep the list up to date with each operation.
Example:
>>> d = odict()
>>> d['a'] = 1
>>> d['b'] = 2
>>> d['c'] = 3
>>> d.items()
[('a', 1), ('b', 2), ('c', 3)]
popitem() has been fixed in this version to throw the correct exception on an empty dictionary.
Note that all operations on the key list are O(n).
|
|
Add comment
|
|
Number of comments: 8
Bug in __init__ regarding _keys, Hamish Lawson, 2002/01/18
If UserDict.__init__ is actually passed a dictionary from __init__, then it will attempt to call update; but _keys isn't yet defined, and so an error will be raised. Therefore _keys must be defined first:
def __init__(self, dict = None):
self._keys = []
UserDict.__init__(self, dict)
Add comment
Bug in __init__ regarding _keys, David Benjamin, 2002/01/21
I made the above change to the source. Thanks for catching this.
Add comment
Ordered Dictionary at Parnassus, Wolfgang Grafen, 2002/02/13
There is a more complete module addressing this topic under
http://home.arcor.de/wolfgang.grafen/Python/Modules/Modules.html called
seqdict.
* seqdict keeps one value for one key
* mseqdict keeps multiple values per key and is the closest emulation of areal world dictionary.
(Search Parnassus for seqdict)
Add comment
Serious bug in copy(), Jon Nelson, 2002/12/19
There is a serious problem with copy()
The returned object instance is one of UserDict not of odict.
I use:
def copy(self):
newInstance = odict()
newInstance.update(self)
return newInstance
and for update:
def update(self, dict):
for (key,val) in dict.items():
self.__setitem__(key,val)
Add comment
keys() should return a copy of self._keys, José Esteves, 2003/01/01
It would be better to have
def keys (self):
return self._keys[:]
to prevent changes to self._keys by callers of the keys() method.
Add comment
Bug in setdefault, Brian Hawthorne, 2004/12/02
setdefault returns the value (new or existing) for the given key.
here is a correct setdefault:
def setdefault(self, key, failobj = None):
if key not in self._keys: self._keys.append(key)
return UserDict.setdefault(self, key, failobj)
Add comment
Extending to Sorted Dictionary, Charlie Taylor, 2006/08/06
I needed a Sorted Dictionary and this Ordered Dictionary made a great starting point.
I substituted:
bisect.insort(self._keys,key)
for:
self._keys.append(key)
in a few places and I was there.
Thanks for the help
Add comment
variations in base class, ruedi w, 2008/02/07
you may want to derive from IterableUserDict to allow for things like [k for k in mydict].
or in python >=2.2: derive directly from dict.
if you cant decide, build a mixin using super() or a wrapper - this gives the ability to order any dict-like object
Add comment
|
|
|
|
|
 |
|