Take the 2-minute tour ×
Programming Puzzles & Code Golf Stack Exchange is a question and answer site for programming puzzle enthusiasts and code golfers. It's 100% free, no registration required.

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"]
share|improve this question
    
Code-golf or code-challenge? –  marinus Jan 3 at 11:15
    
Code-golf. That was mistake. Just correct it –  CrowdStar Jan 3 at 11:16
add comment

19 Answers

up vote 12 down vote accepted

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
share|improve this answer
1  
And yet somehow they call going from this concise witty language to Java "progress"? (-: –  hippietrail Jan 3 at 17:23
add comment

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']
share|improve this answer
1  
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 at 11:33
1  
Hmm, I didn't realize you could pass both a non-None cmp function and a key function. Cool. –  Blckknght Jan 3 at 11:35
1  
A bit shorter: f=lambda n:sorted(set(n),key=n.count)[::-1] –  grc Jan 3 at 13:07
    
Thanks @grc, the alien smiley does save some characters in the Python 3 case. –  Blckknght Jan 3 at 21:48
add comment

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"})

share|improve this answer
    
Darn, you got me there :D –  Yves Klett Jan 3 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 at 15:41
    
Ahh, got it mathematica.stackexchange.com/a/22320/745 –  Ajasja Jan 3 at 15:45
add comment

Mathematica (37)

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

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

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

share|improve this answer
add comment

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
share|improve this answer
add comment

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)

share|improve this answer
    
You can trim a few characters with f=->a{a.sort_by{|z|-a.count(z)}&a} . The & does a uniq. –  histocrat Jan 3 at 23:02
add comment

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.

share|improve this answer
    
I think that [a\])^ should be equivalent to [.;]a\-. Sorting by number of non-matching elements is a nice idea. –  Peter Taylor Jan 4 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 at 21:21
add comment

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

share|improve this answer
add comment

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

share|improve this answer
    
Why the CTE? select name from #t1 group by name order by count(*) desc –  manatwork Jan 3 at 11:44
    
thanks !! @manatwork –  Anonymous Jan 3 at 11:46
add comment

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 )
share|improve this answer
    
have a look at array_count_values()… That's all you have to use (including arsort()) –  bwoebi Jan 3 at 11:50
    
array_count_values() does not delete duplicated values, nor orders them, as I can see. –  Vereos Jan 3 at 12:01
    
It deletes the duplicates … It just doesn't order them… => arsort –  bwoebi Jan 3 at 12:26
    
@bwoebi You are right. Unfortunately writing it that way is 1 character longer than this answer. –  Tim Seguine Jan 3 at 12:55
add comment

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"]
share|improve this answer
add comment

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}

share|improve this answer
add comment

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/

share|improve this answer
    
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 at 18:55
add comment

Haskell - 53 Characters

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

share|improve this answer
add comment

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")
share|improve this answer
add comment

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)
share|improve this answer
add comment

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.

share|improve this answer
    
You could also remove the .ToList(), since the sequence get enumerated via the foreach –  Adam Speight Jan 3 at 22:23
    
That's true, but then I'd have to change the return type into IEnumerable<string>. –  simssi Jan 4 at 0:06
add comment

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"
share|improve this answer
add comment

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)
share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.