[Tutor] Keeping Dictonary Entries Ordered

spir denis.spir at free.fr
Fri Feb 13 11:16:34 CET 2009


Le Fri, 13 Feb 2009 15:41:01 +1300,
John Fouhy <john at fouhy.net> a écrit :

> 2009/2/13 Eric Dorsey <dorseye at gmail.com>:
> > Alan, can you give a short snippet of what that would look like?  I was
> > trying to code out some idea of how you'd retain insertion order using
> > another dict or a list and didn't get anywhere.
> 
> Here's something basic:
> 
> class o_dict(dict):
>     def __init__(self, *args, **kw):
>         dict.__init__(self, *args, **kw)
>         self.__keylist = []
> 
>     def __setitem__(self, key, val):
>         dict.__setitem__(self, key, val)
>         if key not in self.__keylist:
>             self.__keylist.append(key)
> 
>     def __iter__(self):
>         return iter(self.__keylist)
> 
> It will do the right thing if you do 'for key in odict:', but not for
> things like iteritems().  It will break if you delete keys from the
> dictionary, and the 'key not in self.__keylist' test will get slow if
> you have lots and lots of keys.  It will also not do what you want if
> you initialise it as something like: o_dict(foo=1, bar=2)

An issue is that obviously you can't initialize an ordered dict from another dict or a set of keyword arguments, for those are unordered. So I simply took **kwargs off the __init__ method. And let as single possible init stuff a list of (key,value) pairs. Also, as a built_in dict accepts only a single arg, there is no need for *arg: the seq of pairs must be contained in a list or tuple. From the pairs can then the keylist be properly initialised. This led me to something similar to the following:

class Ordict(dict):
	def __init__(self, pairs):
		dict.__init__(self, pairs)
		self._keylist = [k for (k,v) in pairs]
	def __setitem__(self, key, val):
		dict.__setitem__(self, key, val)
		if key not in self._keylist:
			self._keylist.append(key)
	def __iter__(self):
		return iter(self._keylist)
	def __str__(self):
		pair_texts = ["%s:%s" % (k,self[k]) for k in self._keylist]
		return "[%s]" % ", ".join(pair_texts)

od = Ordict([('a',1), ('d',4), ('b',2)])
od[' '] = 0 ; od['c'] = 3
print od._keylist
for k in od: print "%s: %s   " % (k,od[k]),
print; print od

==>

['a', 'd', 'b', ' ', 'c']
a: 1    d: 4    b: 2     : 0    c: 3   
[a:1, d:4, b:2,  :0, c:3]

I remember there were some more minor issues.

Denis
------
la vida e estranya


More information about the Tutor mailing list