Perseus14
Perseus14

Reputation: 487

Sort list by frequency and by value in Python

I have a list of numbers say, [2,2,3,3,4,1] I want to sort by frequency and if the frequency count (ascending) is same then sort by value (also ascending). Soln would be [1,4,2,2,3,3]

For frequency

from collections import Counter
print sorted(arr, key=Counter(arr).get)

But I am not sure how to sort by value for same frequency count elements

Upvotes: 3

Views: 5773

Answers (2)

jpp
jpp

Reputation: 164623

This is one way via numpy.unique and numpy.lexsort:

import numpy as np

arr = np.array([2,2,3,3,4,1])

c = dict(zip(*np.unique(arr, return_counts=True)))

res = arr[np.lexsort((arr, list(map(c.get, arr))))]

# array([1, 4, 2, 2, 3, 3])

Some benchmarking below for a large array:

from collections import Counter
import numpy as np

arr = np.random.randint(0, 9, 100000)

def jp(arr):
    c = dict(zip(*np.unique(arr, return_counts=True)))
    res = arr[np.lexsort((arr, list(map(c.get, arr))))]
    return res

def perseus_sort(l):
    counter = Counter(l)
    return sorted(l, key=lambda x: (counter[x], x))

%timeit jp(arr)            # 39.2 ms
%timeit perseus_sort(arr)  # 118 ms

Upvotes: 2

Omer Tuchfeld
Omer Tuchfeld

Reputation: 3022

To follow up on @bro-grammer's comment (I used a tuple for the keys and called Counter only once):

There's this method which first has to go through the list for counting and then some more for sorting.

from collections import Counter
def perseus_sort(l):
    counter = Counter(l)
    return sorted(l, key=lambda x: (counter[x], x))

There's probably some clever algorithm that can somehow combine both of these but my intuition that it would be pretty complicated and more than you need

Upvotes: 3

Related Questions