0

I have a python dict that looks like

people {"mykey1": myCustomObject, "mykey2": myCustomObject }

Within myCustomObject, I have an integer ID field. So that looks like

class myCustomObject:
    def __init__(self, myID, firstName, lastName):
        self.ID = myID
        self.FirstName = firstName
        self.LastName = lastName

Would it be possible to order this dictionary by the ID property within the custom object???

Unknown Coder
  • 6,201
  • 19
  • 73
  • 120
  • 2
    `dict` instances can *never* be ordered. – Ignacio Vazquez-Abrams Jan 26 '14 at 05:11
  • @IgnacioVazquez-Abrams Except when they can be, by using an OrderedDict, which would be an instance of dict (check it!: ``>>> import collections; d = collections.OrderedDict(); isinstance(d, dict)`` ``True`` – Aaron Hall Jan 26 '14 at 07:19
  • 1
    @AaronHall: It's really just an accident of implementation that `OrderedDict` is a subclass of `dict`, so you probably shouldn't rely on that; if you want to check whether it's a dict-like object, use `isinstance(d, MutableMapping)` instead. But obviously you're right that you shouldn't assume it's _not_ a `dict` subclass, especially given that it happens to be one in fact, and documented as such. :) – abarnert Jan 27 '14 at 23:13
  • @abarnert I know, I'm just being "smart". :) I just implemented a non-dict-inheriting MutableMapping in response to another question (which I coincidentally asked myself here: http://stackoverflow.com/questions/21361106/how-would-i-implement-a-dict-with-abstract-base-classes-in-python/21368848#21368848) – Aaron Hall Jan 27 '14 at 23:23

1 Answers1

6

A dict inherently has an arbitrary order.

If you just want to access it in a specific order one time, you can just sort it. If you don't know how to sort things using anything other than the default ordering, read the Sorting HOW TO. But basically:

for k, v in sorted(d.items(), key=lambda kv: kv[1].ID):
    print('{}: {}'.format(k, v))

If you actually want to store them in that order, you need some time that maintains order. Of course a list will work, but an OrderedDict works like a dict, except that it maintains the order of insertion, which is more convenient for most use cases. So, if you create a new OrderedDict and then insert everything into it in sorted order, that would probably solve your problem:

d1 = { your original dict }
d2 = collections.OrderedDict()
for key in sorted(d1, key=lambda k: d1[k].ID):
    d2[key] = d1[key]

You can simplify this down to one line if you understand comprehensions:

d2 = OrderedDict(sorted(d1.items(), key=lambda kv: kv[1].ID))

Variations on similar examples are shown in the docs under OrderedDict Examples and Recipes.

If you instead want the dictionary to maintain sorted order, you will need some kind of sorted dict class. The stdlib doesn't come with such a class, but there are many options available on ActiveState and PyPI. Some are implemented as an OrderedDict that re-sorts itself every time you update them (or, sometimes, the first time you access them after an update, which allows a long chain of updates to avoid a long chain of sorts). Others use bisect or a search tree (e.g., a binary red-black tree or a 10-ary B-tree) to insert elements in the right place.

abarnert
  • 313,628
  • 35
  • 508
  • 596