Why are there no ordered dictionaries?

Kay Schluehr kay.schluehr at gmx.net
Tue Nov 22 14:18:19 EST 2005


Bengt Richter wrote:
> On Mon, 21 Nov 2005 01:27:22 +0100, Christoph Zwerschke <cito at online.de> wrote:
>
> >Fredrik Lundh wrote:
> >> if you restructure the list somewhat
> >>     d = (
> >>         ('pid', ('Employee ID', 'int')),
> >>         ('name', ('Employee name', 'varchar')),
> >>         ('sal', ('Salary', 'float'))
> >>         )
> >> you can still loop over the list
> >> ...
> >> but you can easily generate an index when you need it:
> >>     index = dict(d)
> >
> >That's exactly the kind of things I find myself doing too often and what
> >I was talking about: You are using *two* pretty redundant data
> >structures, a dictionary and a list/tuple to describe the same thing.
> >Ok, you can use a trick to automatically create the dictionary from the
> >tuple, but still it feels somewhat "unnatural" for me. A "ordered
> >dictionary" would be the more "natural" data structure here.
> >

> But, as has been mentioned**n, this is only one example of an ordering one
> could make default for an "ordered" dictionary. Suppose you say it should
> be ordered by insertion order, so
>   d = OrderedDict(); d[1]='one'; d[2]='two' =>> list(d) => [1, 2]
> ok, now we do d[1]='ein' and what is the order? list(d) => [2, 1] ??
> Or do replacements not count as "insertions"?

"Insertion-order" is not a good term. For a dictionary {key:value} pair
creation, updating and deletion are possible modifying operations.  I
don't see how deletion influences the order so creation and updating
remains. Therefore you have to select beween a creation_order and an
update_order. This can be reduced to one additional keyword e.g.
"creation_order" that is assigned a boolean value which is true by
default.

> The devil is always going
> to be in the details. Maybe you want a model that works more like a list
> of key:value pairs with just optimized access to a pair by key name as
> well as position in the list. Or maybe you want to permit append and
> NOT prevent [('a',1), ('a':2)] and maybe d['a'] => [1, 2] ???

As far as I understand the requirement an odict provides the same
interface as a dict. The only difference is a certain order of the keys
that is induced by operations on a dict and cannot be established by
properties of the keys ( or values ) itself.

> Note that is isn't hard to snap a few pieces together to make an ordered
> dict to your own specs. But IMO it belongs in pyPI or such, not in the system
> library. At least until it gets a lot of mileage -- and MMV ;-)

It's also not very hard to write a hex2ascii converter. That's the
reason why 20 incompatible versions of it ( coded in C ) exists in my
department ;)

Kay

PS. Here is some attempt of my own to implement an odict, following the
discussion here.
The implementation highlights just the model and is incomplete:

class odict(dict):
    def __init__(self, create_order = True):
        dict.__init__(self)
        self.create_order = create_order
        self.__cnt = 0

    def __setitem__(self, key, value):
        val = dict.get(self,key)
        if val and self.create_order:
            dict.__setitem__(self, key, (val[0], value))
        else:
            self.__cnt+=1
            dict.__setitem__(self, key, (self.__cnt, value))

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

    def values(self):
        return list(zip(*sorted(dict.values(self)))[1])

    def keys(self):
        ks = [(dict.get(self,k)[0],k) for k in dict.keys(self)]
        return list(zip(*sorted(ks))[1])

>>> od = odict()
>>> od["a"] = 0
>>> od["b"] = 8
>>> od.keys()
["a", "b"]

>>> od = odict(create_order = False)
>>> od["a"] = 1
>>> od["b"] = 2
>>> od["a"] = 3
>>> od.keys()
["b", "a"]




More information about the Python-list mailing list