Sort the distinct elements of a list in descending order by frequency

Write a function which takes a list or array, and returns a list of the distinct elements, sorted in descending order by frequency.

Example:

Given:

["John","Doe","Dick","Harry","Harry","Doe","Doe","Harry","Doe","John"]


Expected return value:

["Doe","Harry","John","Dick"]

• Code-golf or code-challenge? – marinus Jan 3 '14 at 11:15
• Code-golf. That was mistake. Just correct it – belvi Jan 3 '14 at 11:16

APL (14)

{∪⍵[⍒+⌿∘.≡⍨⍵]}


This is a function that takes a list, e.g.:

      names
John  Doe  Dick  Harry  Harry  Doe  Doe  Harry  Doe  John
{∪⍵[⍒+⌿∘.≡⍨⍵]} names
Doe  Harry  John  Dick


Explanation:

• ∘.≡⍨⍵: compare each element in the array to each other element in the array, giving a matrix
• +⌿: sum the columns of the matrix, giving how many times each element occurs
• ⍒: give indices of downward sort
• ⍵[...]: reorder ⍵ by the given indices
• ∪: get the unique elements
• And yet somehow they call going from this concise witty language to Java "progress"? (-: – hippietrail Jan 3 '14 at 17:23

Python 3 - 47 43; Python 2 - 40 39

For Python 3:

f=lambda n:sorted(set(n),key=n.count)[::-1]


For Python 2:

f=lambda n:sorted(set(n),cmp,n.count,1)


Demo:

>>> names = ["John","Doe","Dick","Harry","Harry","Doe","Doe","Harry","Doe","John"]
>>> f(names)
['Doe', 'Harry', 'John', 'Dick']

• I was trying to post the same, but here is a modification. f=lambda n:sorted(set(n),cmp,n.count,1) 39 characters – YOU Jan 3 '14 at 11:33
• Hmm, I didn't realize you could pass both a non-None cmp function and a key function. Cool. – Blckknght Jan 3 '14 at 11:35
• A bit shorter: f=lambda n:sorted(set(n),key=n.count)[::-1] – grc Jan 3 '14 at 13:07
• Thanks @grc, the alien smiley does save some characters in the Python 3 case. – Blckknght Jan 3 '14 at 21:48

Mathematica, 31

Sort[GatherBy@n][[-1;;1;;-1,1]]


{"Doe", "Harry", "John", "Dick"}

(With n = {"John", "Doe", "Dick", "Harry", "Harry", "Doe", "Doe", "Harry", "Doe", "John"})

• Darn, you got me there :D – Yves Klett Jan 3 '14 at 15:39
• @YvesKlett Thanks. I'm thinking of getting rid of Reverse, but Sort[GatherBy@n][[-1;;1, 1]] does not work:). Any ideas? – Ajasja Jan 3 '14 at 15:41
• Ahh, got it mathematica.stackexchange.com/a/22320/745 – Ajasja Jan 3 '14 at 15:45

Mathematica (26 37)

With n = {"John", "Doe", "Dick", "Harry", "Harry", "Doe", "Doe", "Harry", "Doe", "John"}:

Last/@Gather@n~SortBy~Length//Reverse


{"Doe", "Harry", "John", "Dick"}

Mathematica V10+ (26):

Keys@Sort[Counts[n],#>#2&]

• @garej older version in use. Post as another answer? – Yves Klett Jun 1 '17 at 20:18
• I've added to yours if you do not mind... – garej Jun 1 '17 at 20:23
• @garej. Thanks, excellent solution! – Yves Klett Jun 1 '17 at 20:32

Perl 6 (36 bytes, 35 characters)

» can be replaced with >>, if you cannot handle UTF-8. I'm almost sure this could be shorter, but the Bag class is relatively strange in its behavior (sadly), and isn't really complete, as it's relatively new (but it can count arguments). {} declares an anonymous function.

{(sort -*.value,pairs bag @_)».key}


Sample output (from Perl 6 REPL):

> my @names = ("John","Doe","Dick","Harry","Harry","Doe","Doe","Harry","Doe","John")
John Doe Dick Harry Harry Doe Doe Harry Doe John
> {(sort -*.value,pairs bag @_)».key}(@names)
Doe Harry John Dick


Ruby: 34 37 characters

f=->a{a.sort_by{|z|-a.count(z)}&a}


(edited: previous 30-char solution was the body of the function)

• You can trim a few characters with f=->a{a.sort_by{|z|-a.count(z)}&a} . The & does a uniq. – histocrat Jan 3 '14 at 23:02

GolfScript, 14 chars (19 as named function, also 14 as full program)

:a.|{[.]a\-,}$ This code takes an array on the stack and sorts its unique elements in descending order by number of occurrences. For example, if the input array is: ["John" "Doe" "Dick" "Harry" "Harry" "Doe" "Doe" "Harry" "Doe" "John"]  then the output array will be ["Doe" "Harry" "John" "Dick"]  Note: The code above is a bare sequence of statements. To turn it into a named function, wrap it in braces and assign it to a name, as in: {:a.|{[.]a\-,}$}:f;


Alternatively, to turn the code into a full program that reads a list from standard input (using the list notation shown above) and prints it to standard output, prepend ~ and append  to the code. The [. can be omitted in this case (since we know there will be nothing else on the stack), so that the resulting 14-character program will be:

~:a.|{]a\-,}$  How does it work? • :a saves a copy of the original array in the variable a for later use. • .| computes the set union of the array with itself, eliminating duplicates as a side effect. • { }$ sorts the de-duplicated array using the custom sort keys computed by the code inside the braces. This code takes each array element, uses array subtraction to remove it from the original input array saved in a, and counts the number of remaining elements. Thus, the elements get sorted in decreasing order of frequency.

Ps. See here for the original 30-character version.

• I think that [a\])^ should be equivalent to [.;]a\-. Sorting by number of non-matching elements is a nice idea. – Peter Taylor Jan 4 '14 at 21:07
• Alas, no: ^ collapses duplicates, - doesn't. (And ITYM (, not ).) [a\](\- would work, but wouldn't save any characters. – Ilmari Karonen Jan 4 '14 at 21:21

R: 23 characters

n <- c("John","Doe","Dick","Harry","Harry","Doe","Doe","Harry","Doe","John")

names(sort(table(n),T))
## [1] "Doe"   "Harry" "John"  "Dick"


But it uses the not so nice shortcut of T to TRUE...

if this could fit here : In sql-server

create table #t1 (name varchar(10))
insert into #t1 values ('John'),('Doe'),('Dick'),('Harry'),('Harry'),('Doe'),('Doe'),('Harry'),('Doe'),('John')

select name from #t1 group by name order by count(*) desc


OR

with cte as
(

select name,count(name) as x from #t1 group by name
)

select name from cte order by x desc


see it in action

• Why the CTE? select name from #t1 group by name order by count(*) desc – manatwork Jan 3 '14 at 11:44

PHP, 63 62 61 chars

function R($a){foreach($a as$v)$b[$v]++;arsort($b);return$b;}  Demo: $c = array("John","Doe","Dick","Harry","Harry","Doe","Doe","Harry","Doe","John");
$d = print_r(R($c));

Array ( [Doe] => 4 [Harry] => 3 [John] => 2 [Dick] => 1 )

• have a look at array_count_values()… That's all you have to use (including arsort()) – bwoebi Jan 3 '14 at 11:50
• array_count_values() does not delete duplicated values, nor orders them, as I can see. – Vereos Jan 3 '14 at 12:01
• It deletes the duplicates … It just doesn't order them… => arsort – bwoebi Jan 3 '14 at 12:26
• @bwoebi You are right. Unfortunately writing it that way is 1 character longer than this answer. – Tim Seguine Jan 3 '14 at 12:55
• Why is the way with array_count_values longer? <?$u=array_count_values($_GET);arsort($u);print_r($u); are 54 Bytes in my opinion – Jörg Hülsermann Jun 2 '17 at 9:37

Ruby: 59 characters

f=->n{n.group_by{|i|i}.sort_by{|i|-i[1].size}.map{|i|i[0]}}


Sample run:

irb(main):001:0> f=->n{n.group_by{|i|i}.sort_by{|i|-i[1].size}.map{|i|i[0]}}
=> #<Proc:0x93b2e10@(irb):2 (lambda)>

irb(main):004:0> f[["John","Doe","Dick","Harry","Harry","Doe","Doe","Harry","Doe","John"]]
=> ["Doe", "Harry", "John", "Dick"]


Mathematica, 39 characters

f = Reverse[First /@ SortBy[Tally@#, Last]] &

names = {"John", "Doe", "Dick", "Harry", "Harry",
"Doe", "Doe", "Harry", "Doe", "John"};

f@names


{Doe, Harry, John, Dick}

JavaScript (ECMAScript5): 118 113 characters

function f(n){m={}
for(i in n){m[n[i]]=m[n[i]]+1||1}
return Object.keys(m).sort(function(a,b){return m[b]-m[a]})}


http://jsfiddle.net/mblase75/crg5B/

• With Harmony's fat arrow functions: f=n=>{m={};n.forEach(e=>m[e]=m[e]+1||1);return Object.keys(m).sort((a,b)=>m[b]-m[a])}. (Currently only in Firefox.) – manatwork Jan 3 '14 at 18:55
• You can use m[n[i]]=-~m[n[i]] to increment, and you don't need {}s around the loop body. – Neil May 9 '16 at 21:36

import Data.List
import Data.Ord

f :: (Eq a, Ord a) => [a] -> [a]
f=map head.(sortBy$flip$comparing length).group.sort


Explanation: the first two lines are necessary imports, the next line of code is the type signature (generally not necessary), the actual function is the last line. The function sorts the list by its natural ordering, groups equal elements into lists, sorts the list of lists by descending size, and takes the first element in each list.

total length including imports: 120

w/o imports but with type signature: 86

function itself: 53

Clojure: 43 characters

Function:

#(keys(sort-by(comp - val)(frequencies %)))


Demo (in repl):

user=> (def names ["John","Doe","Dick","Harry","Harry","Doe","Doe","Harry","Doe","John"])
#'user/names
user=> (#(keys(sort-by(comp - val)(frequencies %))) names)
("Doe" "Harry" "John" "Dick")


Perl

to meet given i/o spec I need 120 chars

s!"([^"]+)"[],]!$a{$1}++!e while(<>);print 'MostOccuring = [',join(',',map{qq("$_")}sort{$a{$a}<=>$a{$b}}keys %a),"]\n"  pure shortest code by taking one item per line and printing one item per line I only need 55 chars $a{$_}++ while(<>);print sort{$a{$a}<=>$a{$b}}keys %a)  C#: 111 characters List<string>M(List<string>l){return l.GroupBy(q=>q).OrderByDescending(g=>g.Count()).Select(g=>g.Key).ToList();}  (inside a class) var names = new List<string> {"John", "Doe", "Dick", "Harry", "Harry", "Doe", "Doe", "Harry", "Doe", "John"}; foreach(var s in M(names)) { Console.WriteLine(s); }  Doe Harry John Dick A simple solution using LINQ. • You could also remove the .ToList(), since the sequence get enumerated via the foreach – Adam Speight Jan 3 '14 at 22:23 • That's true, but then I'd have to change the return type into IEnumerable<string>. – paavohtl Jan 4 '14 at 0:06 R (22) names(sort(-table(x)))  As a function it would take 11 more characters. Usage: > x = c("John","Doe","Dick","Harry","Harry","Doe","Doe","Harry","Doe","John") > names(sort(-table(x))) [1] "Doe" "Harry" "John" "Dick"  Scala (71) (x.groupBy(a=>a)map(t=>(t._1,t._2.length))toList)sortBy(-_._2)map(_._1)  Ungolfed: def f(x:Array[String]) = (x.groupBy(a => a) map (t => (t._1, t._2.length)) toList) sortBy(-_._2) map(_._1)  J, 8 bytes ~.\:#/.~  Usage The names are stored as an array of boxed strings.  'John';'Doe';'Dick';'Harry';'Harry';'Doe';'Doe';'Harry';'Doe';'John' ┌────┬───┬────┬─────┬─────┬───┬───┬─────┬───┬────┐ │John│Doe│Dick│Harry│Harry│Doe│Doe│Harry│Doe│John│ └────┴───┴────┴─────┴─────┴───┴───┴─────┴───┴────┘ f =: ~.\:#/.~ f 'John';'Doe';'Dick';'Harry';'Harry';'Doe';'Doe';'Harry';'Doe';'John' ┌───┬─────┬────┬────┐ │Doe│Harry│John│Dick│ └───┴─────┴────┴────┘  Explanation ~.\:#/.~ Input: A #/.~ Finds the size of each set of identical items (Frequencies) ~. List the distinct values in A Note: the distinct values and frequencies will be in the same order \: Sort the distinct values in decreasing order according to the frequencies Return the sorted list implicitly  CJam, 15 bytes (possibly non-competing) q~$e{0=W*}\$1f=
`

This may use CJam features from after this challenge was posted. I'm too lazy to check.