Counter.elements

The inverse of counting: turn {element: count} back into a stream of elements. Elements come out grouped in the order they were first inserted, not sorted and not in the original sequence order.

Counter methodPython 3.1+Live demo
Common call
list(Counter(a=2, b=1).elements())
Returns
['a', 'a', 'b'] — via an iterator
Replaces
[k for k, n in d.items() for _ in range(n)]
Watch out
counts must be ints; a float count raises TypeError
Counter.elements()
→ iterator

Demo

Live evaluation
Count a text, then expand it again: same letters, grouped.
Try:
Inputs
textstrany text
Code
from collections import Counter
list(Counter('banana').elements())
Result
['b', 'a', 'a', 'a', 'n', 'n']

"banana" expands to b, a, a, a, n, n: all copies of an element sit together, in the order each element was first counted. elements() uses itertools.repeat under the hood, which is why a count of 1.5 fails with "'float' object cannot be interpreted as an integer".

Common patterns

Rebuild a sorted multiset
sorted() gives a canonical order.
from collections import Counter
sorted(Counter(tiles).elements())
Draw from weighted counts
Materialise the population once, then sample from it.
import random
from collections import Counter
pool = list(Counter(red=3, blue=1).elements())
random.choice(pool)
What is left after removing another multiset
Subtract with -, then expand.
from collections import Counter
remaining = list((Counter(hand) - Counter(played)).elements())

Examples

1. Expand counts
from collections import Counter list(Counter(a=2, b=1).elements())
Returns
['a', 'a', 'b']
2. Grouped, not original order
from collections import Counter ''.join(Counter('abab').elements())
Returns
'aabb'
3. Zero and negative counts skipped
from collections import Counter list(Counter(a=0, b=-1, c=2).elements())
Returns
['c', 'c']
4. It is an iterator
from collections import Counter type(Counter('ab').elements()).__name__
Returns
'chain'
5. Sorted multiset
from collections import Counter sorted(Counter('banana').elements())
Returns
['a', 'a', 'a', 'b', 'n', 'n']
6. Float counts fail
from collections import Counter list(Counter(a=1.5).elements())
Returns
TypeError: 'float' object cannot be interpreted as an integer

Pitfalls

1. Expecting the original sequence back
A Counter only remembers how many, not where. elements() groups equal items.
expects abab
from collections import Counter
''.join(Counter('abab').elements()) == 'abab'
False
compare counts
from collections import Counter
Counter(Counter('abab').elements()) == Counter('abab')
True
2. Printing the iterator
elements() returns a lazy itertools.chain object; wrap it in list() to see the items.
len(iterator)
from collections import Counter
len(Counter('ab').elements())
TypeError: object of type 'itertools.chain' has no len()
len(list(...))
from collections import Counter
len(list(Counter('ab').elements()))
2

When to use

Use it
  • Turning counts back into items (for sorting, sampling, joining)
  • Checking a multiset result element by element
Reach for something else
  • Just the number of items → c.total()
  • Huge counts → iterate c.items() instead of materialising millions of copies

Notes

CPython impl
chain.from_iterable(starmap(repeat, self.items())) — itertools.repeat is why non-int counts raise TypeError and non-positive counts yield nothing
Order
Elements are returned in the order first encountered (insertion order), each repeated its count

FAQ

list(counter.elements()) repeats each element count times. list(counter) gives only the distinct elements (the keys).