20

I have a list of integers(or could be even strings), which I would like to sort by the frequency of occurrences in Python, for instance:

a = [1, 1, 2, 3, 3, 3, 4, 4, 4, 5, 5, 5, 5]

Here the element 5 appears 4 times in the list, 4 appears 3 times. So the output sorted list would be :

result = [5, 5, 5, 5, 3, 3, 3, 4, 4, 4, 1, 1, 2]

I tried using a.count(), but it gives the number of occurrence of the element. I would like to sort it. Any idea how to do it ?

Thanks

Grijesh Chauhan
  • 55,177
  • 19
  • 133
  • 197
Kiran
  • 7,516
  • 35
  • 105
  • 167

6 Answers6

36
from collections import Counter
print [item for items, c in Counter(a).most_common() for item in [items] * c]
# [5, 5, 5, 5, 3, 3, 3, 4, 4, 4, 1, 1, 2]

Or even better (efficient) implementation

from collections import Counter
from itertools import repeat, chain
print list(chain.from_iterable(repeat(i, c) for i,c in Counter(a).most_common()))
# [5, 5, 5, 5, 3, 3, 3, 4, 4, 4, 1, 1, 2]

Or

from collections import Counter
print sorted(a, key=Counter(a).get, reverse=True)
# [5, 5, 5, 5, 3, 3, 3, 4, 4, 4, 1, 1, 2]

If you prefer in-place sort

a.sort(key=Counter(a).get, reverse=True)
thefourtheye
  • 221,210
  • 51
  • 432
  • 478
8

Using Python 3.3 and the built in sorted function, with the count as the key:

>>> a = [1,1,2,3,3,3,4,4,4,5,5,5,5]
>>> sorted(a,key=a.count)
[2, 1, 1, 3, 3, 3, 4, 4, 4, 5, 5, 5, 5]
>>> sorted(a,key=a.count,reverse=True)
[5, 5, 5, 5, 3, 3, 3, 4, 4, 4, 1, 1, 2]
thegrinner
  • 10,517
  • 5
  • 42
  • 64
3
In [15]: a = [1,1,2,3,3,3,4,4,4,5,5,5,5]

In [16]: counts = collections.Counter(a)

In [17]: list(itertools.chain.from_iterable([[k for _ in range(counts[k])] for k in sorted(counts, key=counts.__getitem__, reverse=True)]))
Out[17]: [5, 5, 5, 5, 3, 3, 3, 4, 4, 4, 1, 1, 2]

Alternatively:

answer = []
for k in sorted(counts, key=counts.__getitem__, reverse=True):
    answer.extend([k for _ in range(counts[k])])

Of course, [k for _ in range(counts[k])] can be replaced with [k]*counts[k].
So line 17 becomes

list(itertools.chain.from_iterable([[k]*counts[k] for k in sorted(counts, key=counts.__getitem__, reverse=True)]))
inspectorG4dget
  • 104,525
  • 25
  • 135
  • 234
1

If you happen to be using numpy already, or if using it is an option, here's another alternative:

In [309]: import numpy as np

In [310]: a = [1, 2, 3, 3, 1, 3, 5, 4, 4, 4, 5, 5, 5]

In [311]: vals, counts = np.unique(a, return_counts=True)

In [312]: order = np.argsort(counts)[::-1]

In [313]: np.repeat(vals[order], counts[order])
Out[313]: array([5, 5, 5, 5, 4, 4, 4, 3, 3, 3, 1, 1, 2])

That result is a numpy array. If you want to end up with a Python list, call the array's tolist() method:

In [314]: np.repeat(vals[order], counts[order]).tolist()
Out[314]: [5, 5, 5, 5, 4, 4, 4, 3, 3, 3, 1, 1, 2]
Warren Weckesser
  • 102,583
  • 19
  • 173
  • 194
0

Not interesting way...

a = [1,1,2,3,3,3,4,4,4,5,5,5,5]

from collections import Counter
result = []
for v, times in sorted(Counter(a).iteritems(), key=lambda x: x[1], reverse=True):
    result += [v] * times

One liner:

reduce(lambda a, b: a + [b[0]] * b[1], sorted(Counter(a).iteritems(), key=lambda x: x[1], reverse=True), [])
Kei Minagawa
  • 4,241
  • 3
  • 23
  • 41
0

Occurrence in array and within a sets of equal size:

rev=True

arr = [6, 6, 5, 2, 9, 2, 5, 9, 2, 5, 6, 5, 4, 6, 9, 1, 2, 3, 4, 7 ,8 ,8, 8, 2]
print arr

arr.sort(reverse=rev)

ARR = {}
for n in arr:
  if n not in ARR:
    ARR[n] = 0
  ARR[n] += 1

arr=[]
for k,v in sorted(ARR.iteritems(), key=lambda (k,v): (v,k), reverse=rev):
  arr.extend([k]*v)
print arr

Results:

[6, 6, 5, 2, 9, 2, 5, 9, 2, 5, 6, 5, 4, 6, 9, 1, 2, 3, 4, 7, 8, 8, 8, 2]
[2, 2, 2, 2, 2, 6, 6, 6, 6, 5, 5, 5, 5, 9, 9, 9, 8, 8, 8, 4, 4, 7, 3, 1]
Stephen Rauch
  • 44,696
  • 30
  • 102
  • 125
Ivan Motin
  • 21
  • 1
  • 2