0

Hello I found that in python 3.6:

cnt = collections.Counter(['red', 'blue', 'red', 'green', 'blue', 'blue'])
print(cnt)  # >>> Counter({'blue': 3, 'red': 2, 'green': 1})

in the document, it says 'elements() Return an iterator over elements repeating each as many times as its count. Elements are returned in arbitrary order.'

However:

print(list(cnt.elements()))  

will always give me:

['red', 'red', 'blue', 'blue', 'blue', 'green']

I don't think it is arbitrary order anymore, it kind of depends on the sequece of original data's occurrence:

cnt = collections.Counter(['red', 'green', 'red', 'blue', 'blue', 'blue'])
print(list(cnt.elements())) 
# >>> ['red', 'red', 'green', 'blue', 'blue', 'blue']

If I switch 'blue' and 'green' in the list, I will get 'green' before 'blue' in the cnt.elements()

Is my discovery correct or I was not doing it the right way?

jxie0755
  • 1,682
  • 1
  • 16
  • 35
  • from Raymond Hettinger‏ "raymondh #python news: gvanrossum just pronounced that dicts are now guaranteed to retain insertion order. This is the end of a long journey." 8:40 AM - 15 Dec 2017. https://twitter.com/raymondh/status/941709626545864704 – ShpielMeister Dec 25 '17 at 03:50
  • from Guido van Rossum "gvanrossum Replying to yaroslavvb raymondh ogrisel First good question in this thread. Sets remain unordered. (Why? The usage patterns are different. Also, different implementation.)". 10:05 PM - 15 Dec 2017. twitter.com/raymondh/status/941709626545864704 – ShpielMeister Dec 25 '17 at 03:56

2 Answers2

1

This is due to a change in the implementation of dict in Python 3.6:

The dict type now uses a “compact” representation based on a proposal by Raymond Hettinger which was first implemented by PyPy. The memory usage of the new dict() is between 20% and 25% smaller compared to Python 3.5.

The order-preserving aspect of this new implementation is considered an implementation detail and should not be relied upon (this may change in the future, but it is desired to have this new dict implementation in the language for a few releases before changing the language spec to mandate order-preserving semantics for all current and future Python implementations; this also helps preserve backwards-compatibility with older versions of the language where random iteration order is still in effect, e.g. Python 3.5).

Community
  • 1
  • 1
jwodder
  • 54,758
  • 12
  • 108
  • 124
  • So basically, it is changed during the update of just last version (3.5 to 3.6). Should I report to whoever to remind updating the documents in 3.6? – jxie0755 Dec 25 '17 at 03:36
  • @Code_Control_jxie0755: I don't think they'll consider this a problem with the documentation worth fixing. Even putting aside potential waffling over the meaning of "arbitrary," the quote above specifically states that "the order-preserving aspect ... should not be relied upon," so they're not going to change the docs to say "Insertion order is preserved," as that would implicitly tell people to rely upon it. – jwodder Dec 25 '17 at 03:40
  • 1
    @Code_Control_jxie0755 the Counter documentation is correct and consistent - the container's elements() method itself does not guarantee any form of ordering - just that the keys are repeated the correct number of times and contiguously - that's the only contract it needs to fulfill. The fact that it can in the most common use case for a specific version of Python with a specific implementation of its default base store do so as part of a side effect is neither here nor there. – Jon Clements Dec 25 '17 at 03:58
1

Python 3.6 dict are now ordered!

Since collections.Counter is a direct subclass of the built-in type dict, it is stored in order as well.


As the python 3.6 update note stated that the order of the dict should not be relied on because it's only an implementation detail; you should not rely on the fact that .elements() returns ordered elements.

But as of Python 3.7, you can be sure that dict will always keep insertion order!

Community
  • 1
  • 1
Taku
  • 31,927
  • 11
  • 74
  • 85