Сортировка списка по частоте появления в списке

У меня есть список целых чисел (или может быть четными строками), которые я бы хотел отсортировать по частоте вхождений в Python, например:

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

Здесь элемент 5 появляется 4 раза в списке, 4 появляется 3 раза. Таким образом, отсортированный список результатов будет:

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

Я попробовал использовать a.count(), но он дает количество элементов вхождения. Я хотел бы отсортировать его. Любая идея, как это сделать?

Спасибо

Ответ 1

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]

Или даже лучше (эффективная) реализация

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]

или

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]

Если вы предпочитаете сортировку на месте

a.sort(key=Counter(a).get, reverse=True)

Ответ 2

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]

В качестве альтернативы:

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

Конечно, [k for _ in range(counts[k])] можно заменить на [k]*counts[k].
Таким образом, строка 17 становится

list(itertools.chain.from_iterable([[k]*counts[k] for k in sorted(counts, key=counts.__getitem__, reverse=True)]))

Ответ 3

Используя Python 3.3 и встроенную функцию sorted, счетчик как ключ:

>>> 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]

Ответ 4

Не интересный способ...

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

Один вкладыш:

reduce(lambda a, b: a + [b[0]] * b[1], sorted(Counter(a).iteritems(), key=lambda x: x[1], reverse=True), [])