14
\$\begingroup\$

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"]
\$\endgroup\$
2
  • \$\begingroup\$ Code-golf or code-challenge? \$\endgroup\$
    – marinus
    Jan 3, 2014 at 11:15
  • \$\begingroup\$ Code-golf. That was mistake. Just correct it \$\endgroup\$ Jan 3, 2014 at 11:16

27 Answers 27

13
\$\begingroup\$

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
\$\endgroup\$
1
  • 4
    \$\begingroup\$ And yet somehow they call going from this concise witty language to Java "progress"? (-: \$\endgroup\$ Jan 3, 2014 at 17:23
8
\$\begingroup\$

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

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

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

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&]
\$\endgroup\$
3
  • \$\begingroup\$ @garej older version in use. Post as another answer? \$\endgroup\$
    – Yves Klett
    Jun 1, 2017 at 20:18
  • \$\begingroup\$ I've added to yours if you do not mind... \$\endgroup\$
    – garej
    Jun 1, 2017 at 20:23
  • \$\begingroup\$ @garej. Thanks, excellent solution! \$\endgroup\$
    – Yves Klett
    Jun 1, 2017 at 20:32
3
\$\begingroup\$

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
\$\endgroup\$
3
\$\begingroup\$

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)

\$\endgroup\$
1
  • \$\begingroup\$ You can trim a few characters with f=->a{a.sort_by{|z|-a.count(z)}&a} . The & does a uniq. \$\endgroup\$
    – histocrat
    Jan 3, 2014 at 23:02
3
\$\begingroup\$

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.

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

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

\$\endgroup\$
2
\$\begingroup\$

K (ngn/k), 5 bytes

>#'=:

Try it online!

  • =: group the input, building a dictionary mapping unique values to the indices in which they appear
  • #' take the count of each set of indices
  • > sort the keys of the dictionary by their values, descending
\$\endgroup\$
1
\$\begingroup\$

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

\$\endgroup\$
1
  • 1
    \$\begingroup\$ Why the CTE? select name from #t1 group by name order by count(*) desc \$\endgroup\$
    – manatwork
    Jan 3, 2014 at 11:44
1
\$\begingroup\$

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

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"]
\$\endgroup\$
1
\$\begingroup\$

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}

\$\endgroup\$
1
\$\begingroup\$

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/

\$\endgroup\$
2
  • \$\begingroup\$ 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.) \$\endgroup\$
    – manatwork
    Jan 3, 2014 at 18:55
  • \$\begingroup\$ You can use m[n[i]]=-~m[n[i]] to increment, and you don't need {}s around the loop body. \$\endgroup\$
    – Neil
    May 9, 2016 at 21:36
1
\$\begingroup\$

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.

\$\endgroup\$
2
  • \$\begingroup\$ You could also remove the .ToList(), since the sequence get enumerated via the foreach \$\endgroup\$ Jan 3, 2014 at 22:23
  • \$\begingroup\$ That's true, but then I'd have to change the return type into IEnumerable<string>. \$\endgroup\$
    – paavohtl
    Jan 4, 2014 at 0:06
1
\$\begingroup\$

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

\$\endgroup\$
1
\$\begingroup\$

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")
\$\endgroup\$
1
\$\begingroup\$

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
\$\endgroup\$
1
\$\begingroup\$

05AB1E, 5 bytes

ÙΣ¢}R

Try it online.

Explanation:

Ù    # Uniquify the (implicit) input-list
 Σ   # Sort this uniquified list by:
  ¢  #  Get its count in the (implicit) input-list
 }R  # After the ascending sort: reverse the list, so it'll become descending
     # (after which the result is output implicitly)
\$\endgroup\$
1
\$\begingroup\$

Stax, 7 bytes

èó±☻₧╛╗

Run and debug it

\$\endgroup\$
1
\$\begingroup\$

Jelly, 6 bytes

Qċ@ÞṚ⁺

Try it online!

There are quite a few ways to formulate this, but I find this to be the most amusing of several 6-byte alternatives. ċ@Þ@QṚ comes rather close.

Q         Unique items of the input.
   Þ      Sort them by
 ċ@       how many times they appear in the input
    Ṛ     reversed.
     ⁺    Duplicate the last link: reverse the sorted result.
\$\endgroup\$
1
\$\begingroup\$

CJam, 15 bytes

q~$e`{0=W*}$1f=

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

\$\endgroup\$
1
\$\begingroup\$

Husk, 5 bytes

u↔Ö#¹

Try it online!

\$\endgroup\$
1
\$\begingroup\$

Factor, 33 bytes

[ sorted-histogram keys reverse ]

Try it online!

Explanation

                 ! { "John" "Doe" "Dick" "Harry" "Harry" "Doe" "Doe" "Harry" "Doe" "John" }
sorted-histogram ! { { "Dick" 1 } { "John" 2 } { "Harry" 3 } { "Doe" 4 } }
keys             ! { "Dick" "John" "Harry" "Doe" }
reverse          ! { "Doe" "Harry" "John" "Dick" }
\$\endgroup\$
0
\$\begingroup\$

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)
\$\endgroup\$
0
\$\begingroup\$

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)
\$\endgroup\$
0
\$\begingroup\$

Perl 5, 51 bytes

sub f{my%k;$k{$_}++for@_;sort{$k{$b}-$k{$a}}keys%k}

Try it online!

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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