2

I have code like the following, I want to get the order in which the keys are inserted

from collections import Counter, OrderedDict
s = 'abcdabcd'
d = OrderedDict(Counter(s))
print(d)

output: OrderedDict([('a', 2), ('b', 2), ('c', 2), ('d', 2)])

Is the right way to do that, can we get same order for every time run the code?

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
Ramarao Amara
  • 3,106
  • 1
  • 8
  • 5

1 Answers1

2

Yes, if you repeatedly run your code, it'll produce the same order provided you use Python 3.6 or newer.

That's because iterating over Counter() objects will always give you the items in insertion order, and that order is determined by the input. If the s input doesn't change, neither will the output of OrderedDict(Counter(s)).

Note that this is the insertion order of keys, not the order produced by Counter.most_common(); the items are not sorted when passed from Counter() to OrderedDict. The order remains stable because as of Python 3.6, the Python implementation of dictionaries was changed to use less memory, and that in turn had the side effect of the insertion order being recorded. As of Python 3.7, maintaining insertion order in dictionaries became part of the language specification. See How to keep keys/values in same order as declared?

So keys are listed in order of first appearance:

>>> from collections import Counter, OrderedDict
>>> OrderedDict(Counter("aaabbc"))
OrderedDict([('a', 3), ('b', 2), ('c', 1)])
>>> OrderedDict(Counter("abbccc"))
OrderedDict([('a', 1), ('b', 2), ('c', 3)])
>>> OrderedDict(Counter("cba"))
OrderedDict([('c', 1), ('b', 1), ('a', 1)])

If you want to capture a different ordering, you need to sort the items before passing them to the OrderedDict() object. E.g. for most common ordering (highest count first), pass in the result of Counter.most_common():

>>> s = "abbcaaacbbbbc"
>>> OrderedDict(Counter(s).most_common())
OrderedDict([('b', 6), ('a', 4), ('c', 3)])

If people are wondering why you still might use an OrderedDict: with this type you can re-order keys (via OrderedDict.move_to_end()). You can also use reversed() on an ordered dict (as well as its dictionary views).

(Note: I got this wrong on first draft, after verification I adjusted this answer).

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343