Reputation: 487
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
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
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