[Tutor] Why is an OrderedDict not sliceable?

Steven D'Aprano steve at pearwood.info
Thu Jan 21 19:00:00 EST 2016


Further thoughts on your question...


On Wed, Jan 20, 2016 at 01:33:17PM +0000, Albert-Jan Roskam wrote:
> Hi,
> 
> Like the subject says: Why is an OrderedDict not sliceable? (From the 
> collections library). Was that an intentional omission, or a mistake? 
> [1]
> 
> Background: I do not use OrderedDict very often, but I thought I could 
> use it to look up street and city names using postcodes ([0-9]{4} 
> [a-z]{2} format). I needed it to be ordered because I also wanted to 
> be able to use bisect, which is needed when the postcode letters are 
> missing. In short: a fast dict lookup for complete postcodes and less 
> fast bisect lookup for in complete postcodes.

I'm not sure I understand your use-case here.

You have postcodes that look like this:

"1234az"

Correct? Why do you want them *ordered*? 

I think you are confusing OrderedDict for a "Sorted Dict". OrderedDict 
doesn't keep the keys in sorted order, it keeps them in the order that 
they were inserted. So unless you are super-careful to insert the 
postcodes in sorted order, the order of them in the dict will be 
whatever order you insert them:

py> from collections import OrderedDict
py> d = OrderedDict()
py> d['1234az'] = "1 Smith Street"
py> d['9999zz'] = "991203 Short Street"
py> d['3456mx'] = "24 Hour Lane"
py> for key in d:
...     print(key, d[key])
...
1234az 1 Smith Street
9999zz 991203 Short Street
3456mx 24 Hour Lane


So even if OrderedDict supported slicing, that would not do what you 
think it does.


Also, you have a problem -- what happens if the incomplete postcode is 
missing the first digit? (I suppose for that case, you just have to do a 
slow linear search.) What about transposed digits or other errors? I'm 
glad I don't have to solve that problem!


Anyway, I suggest doing something like this:

(1) Keep the known postcodes in a regular dict, not an ordered dict.

(2) Once you have built the dict, then copy the keys and sort them:

postcodes = {
    '1234az': "1 Smith Street",
    '9999zz': "991203 Short Street",
    '3456mx': "24 Hour Lane",
    }

array = sorted(postcodes.keys())


(3) Each time you add a new postcode to the dict, use bisect to add it 
to the array as well. To ensure you never forget, use a helper function:

def insert(postcode, entry):
    if postcode in postcodes:
        # deal with duplicate/existing key
        ...
    else:
        postcodes[postcode] = entry
        bisect.insort(array, postcode)


Same for deleting.



-- 
Steve


More information about the Tutor mailing list