How do you retrieve items from a dictionary in the order that they're inserted?
Asked Answered
I

11

68

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

Intradermal answered 13/9, 2008 at 20:38 Comment(2)
possible duplicate of Why dictionary values aren't in the inserted order?Curule
This question (and outdated accepted answer) is still the #1 result of googling "python dict items by insertion order". If you're reading this, please upvote Brian's 2018 answer.Ingleside
H
71

The standard Python dict does this by default if you're using CPython 3.6+ (or Python 3.7+ for any other implementation of Python).

On older versions of Python you can use collections.OrderedDict.

Hypogeum answered 13/9, 2008 at 20:48 Comment(0)
W
27

As of Python 3.7, the standard dict preserves insertion order. From the docs:

Changed in version 3.7: Dictionary order is guaranteed to be insertion order. This behavior was implementation detail of CPython from 3.6.

So, you should be able to iterate over the dictionary normally or use popitem().

Whitehorse answered 10/8, 2018 at 0:53 Comment(1)
Lets get this answer upvoted. Additionally from the docs, section 5.5 Dictionaries: "Performing list(d) on a dictionary returns a list of all the keys used in the dictionary, in insertion order (if you want it sorted, just use sorted(d) instead)."Ingleside
P
20

Use OrderedDict(), available since version 2.7

Just a matter of curiosity:

from collections import OrderedDict
a = {}
b = OrderedDict()
c = OrderedDict()

a['key1'] = 'value1'
a['key2'] = 'value2'

b['key1'] = 'value1'
b['key2'] = 'value2'

c['key2'] = 'value2'
c['key1'] = 'value1'

print a == b  # True
print a == c  # True
print b == c  # False
Presentable answered 29/10, 2014 at 17:42 Comment(0)
P
17

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')]
Purveyance answered 14/9, 2008 at 0:58 Comment(2)
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.Moquette
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.Purveyance
D
5

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.

Divisor answered 13/9, 2008 at 20:39 Comment(1)
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.Neilneila
A
5

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

Algophobia answered 15/9, 2008 at 19:31 Comment(1)
This makes it impossible to look up entries in the dict without knowing exactly when you inserted them. It's no better than a list of key-value pairs.Worthington
W
3

I've used StableDict before with good success.

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

Wulfenite answered 15/9, 2008 at 18:15 Comment(0)
G
1

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

Gospel answered 18/3, 2009 at 19:42 Comment(0)
P
0

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

Politician answered 19/9, 2008 at 15:56 Comment(0)
T
-1

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?

Thyself answered 15/9, 2008 at 16:7 Comment(0)
R
-1

What you can do is insert the values with a key representing the order inputted, and then call sorted() on the items.

>>> obj = {}
>>> obj[1] = 'Bob'
>>> obj[2] = 'Sally'
>>> obj[3] = 'Joe'
>>> for k, v in sorted(obj.items()):
...     print v
... 
Bob
Sally
Joe
>>> 
Reorganization answered 4/6, 2014 at 2:50 Comment(3)
If we didn't already need the key for other purposes, we would use a list. This does nothing a list doesn't do better.Worthington
@user2357112, however, this expresses another method of doing what the OP asked. The OP did not ask how to print items in the order they were inserted, the OP said how to print items in a dict. Big difference.Reorganization
You've changed the format of the dict to the point of making it unuseful for the original purpose, though. If the dict was originally associating, say, names to phone numbers, you've gained a consistent iteration order, but you have no idea what Bob's phone number is.Worthington

© 2022 - 2024 — McMap. All rights reserved.