views:

1367

answers:

8

Is it possible to retrieve items from a Python dictionary in the order that they were inserted?

+5  A: 

You can't do this with the base dict class -- it's ordered by hash. You could build your own dictionary that is really a list of key,value pairs or somesuch, which would be ordered.

Cody Brocious
Your dictionary implementation can instead use a standard dictionary and a list - the dictionary stores the key->value associations, and the list stores keys in the order they are inserted.
binil
+17  A: 

The standard python dict isn't able to do this.

There is a proposal (PEP 372) to add an "ordered dictionary" (that keeps track of the order of insertion) to the collections module in the standard library. It includes links to various implementations of ordered dictionaries (see also these two recipes in the Python Cookbook).

You might want to stick with the reference implementation in the PEP if you want your code to be compatible with the "official" version (if the proposal is eventually accepted).

dF
+6  A: 

The other answers are correct; it's not possible, but you could write this yourself. However, in case you're unsure how to actually implement something like this, here's a complete and working implementation that subclasses dict which I've just written and tested. (Note that the order of values passed to the constructor is undefined but will come before values passed later, and you could always just not allow ordered dicts to be initialized with values.)

class ordered_dict(dict):
    def __init__(self, *args, **kwargs):
        dict.__init__(self, *args, **kwargs)
        self._order = self.keys()

    def __setitem__(self, key, value):
        dict.__setitem__(self, key, value)
        if key in self._order:
            self._order.remove(key)
        self._order.append(key)

    def __delitem__(self, key):
        dict.__delitem__(self, key)
        self._order.remove(key)

    def order(self):
        return self._order[:]

    def ordered_items(self):
        return [(key,self[key]) for key in self._order]


od = ordered_dict()
od["hello"] = "world"
od["goodbye"] = "cruel world"
print od.order()            # prints ['hello', 'goodbye']

del od["hello"]
od["monty"] = "python"
print od.order()            # prints ['goodbye', 'monty']

od["hello"] = "kitty"
print od.order()            # prints ['goodbye', 'monty', 'hello']

print od.ordered_items()
# prints [('goodbye','cruel world'), ('monty','python'), ('hello','kitty')]
Eli Courtwright
Is order_dict( ('key_a','value_a'), ('key_b','value_b') ) ordered correctly? Looks like _order would be set to self.keys() in __init__, which is ordered in the hash-ordering, not the order it was entered? Just curious.
Brian M. Hunt
You're correct, which is why I said, "the order of values passed to the constructor is undefined but will come before values passed later". It would be possible to order those properly, but I wasn't sure whether that was a desired behavior, since arguably such objects are inserted simultaneously.
Eli Courtwright
A: 

if you don't need the dict functionality, and only need to return tuples in the order you've inserted them, wouldn't a queue work better?

+2  A: 

I've used StableDict before with good success.

http://pypi.python.org/pypi/StableDict/0.2

+1  A: 

Or, just make the key a tuple with time.now() as the first field in the tuple.

Then you can retrieve the keys with dictname.keys(), sort, and voila!

Gerry

Gerry
+1  A: 

It's not possible unless you store the keys in a separate list for referencing later.

Jeremy Cantrell
+1  A: 

Or use any of the implementations for the PEP-372 described here, like the odict module from the pythonutils.

I successfully used the pocoo.org implementation, it is as easy as replacing your

my_dict={}
my_dict["foo"]="bar"

with

my_dict=odict.odict()
my_dict["foo"]="bar"

and require just this file

Davide