122

I'm looking for an elegant way of determining which element has the highest occurrence (mode) in a JavaScript array.

For example, in

['pear', 'apple', 'orange', 'apple']

the 'apple' element is the most frequent one.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
vise
  • 12,713
  • 11
  • 52
  • 64
  • You could adapt some ideas from this Stackoverflow question. http://stackoverflow.com/questions/840781/easiest-way-to-find-duplicate-values-in-a-javascript-array – Nosredna Jun 27 '09 at 23:23
  • I've not read the solutions too closely, but do any of them incorporate the following nuance (optimization?), based on the requirement merely to determine which element has the most occurrences, rather than how many occurrences is the most .... and that nuance is, as the array is looped over, counting can stop when the difference between the highest and second-highest occurences, is less than the number of elements left to loop over, looping can cease, the current highest will be the highest – Dexygen Aug 09 '10 at 00:54
  • There's a language-agnostic question at [algorithm - The Most Efficient Way To Find Top K Frequent Words In A Big Word Sequence - Stack Overflow](https://stackoverflow.com/questions/185697/the-most-efficient-way-to-find-top-k-frequent-words-in-a-big-word-sequence) – user202729 Jan 20 '21 at 09:07

42 Answers42

121

This is just the mode. Here's a quick, non-optimized solution. It should be O(n).

function mode(array)
{
    if(array.length == 0)
        return null;
    var modeMap = {};
    var maxEl = array[0], maxCount = 1;
    for(var i = 0; i < array.length; i++)
    {
        var el = array[i];
        if(modeMap[el] == null)
            modeMap[el] = 1;
        else
            modeMap[el]++;  
        if(modeMap[el] > maxCount)
        {
            maxEl = el;
            maxCount = modeMap[el];
        }
    }
    return maxEl;
}
Matthew Flaschen
  • 278,309
  • 50
  • 514
  • 539
  • 1
    Nice... but it only works for strings - not necessarily a limitation but something to consider. – James Jun 28 '09 at 00:00
  • Many thanks, I wasn't expecting a complete solution. Works on both strings and numbers with only a single pass which is quite nice. – vise Jun 28 '09 at 01:34
  • 2
    I've added a version of this algorithm to handle ties. – samandmoore Aug 10 '10 at 18:10
  • 3
    I had to replace `f(modeMap[el] == null) with if(!modeMap[el]) as it was diving me wierd number when passing [2, 3, 3] because modeMap[el] was undefined not null. – Naz Jun 19 '14 at 21:53
  • 1
    Very useful this, if you can guarantee that there will be a single value that will appear the most number of times. An array of [A,A,B,B,C], only returns A, but surely the mode is A and B here? – Mike Upjohn Sep 20 '16 at 10:56
  • 3
    I think it's reasonable to have a tie-breaker, which in this case is the element that comes first in the array. But you could easily alter this algorithm to give you each tied for most. – Wylliam Judd Nov 14 '17 at 19:06
  • It's actually O(N log N) because of the HashMap – noɥʇʎԀʎzɐɹƆ Jul 12 '18 at 21:09
  • i had to fix some code like this var maxEl = array[0], maxCount = 0; – ysimonx Nov 20 '19 at 19:53
  • @noɥʇʎԀʎzɐɹƆ Please explain why it should be O(n log n)? – seveneights Aug 05 '21 at 17:53
  • @seveneights Looking up or storing something in a hashmap is a O(log n) operation. On the random-access model of computing, looking up something in an array is an O(1) operation. In practice, the difference might not be important– it depends on the size of your data. – noɥʇʎԀʎzɐɹƆ Aug 05 '21 at 22:54
  • @noɥʇʎԀʎzɐɹƆ I believe that usually the worst case complexity is stated as O(n), O(log n) should only be the case for implementations using binary search trees (i.e. java). – seveneights Aug 07 '21 at 15:35
  • 1
    @seveneights `nodeMap` is a JavaScript object, which can be implemented as a B-tree. When it is implemented as an "O(1)" hash table, the engine does not know the size of the `nodeMap`, so therefore it has to reallocate the memory. Each time it reallocates memory it costs `log N` time, so ultimately O(n log n) is still an accurate description. Either way, the `log N` factor is too small to actually matter most of the time. – noɥʇʎԀʎzɐɹƆ Aug 07 '21 at 23:20
  • But what happens if 2 values appear the same number of times? – Bill Bronson Jun 09 '22 at 11:03
97

There have been some developments in javascript since 2009 - I thought I'd add another option. I'm less concerned with efficiency until it's actually a problem so my definition of "elegant" code (as stipulated by the OP) favours readability - which is of course subjective...

function mode(arr){
    return arr.sort((a,b) =>
          arr.filter(v => v===a).length
        - arr.filter(v => v===b).length
    ).pop();
}

mode(['pear', 'apple', 'orange', 'apple']); // apple

In this particular example, should two or more elements of the set have equal occurrences then the one that appears latest in the array will be returned. It's also worth pointing out that it will modify your original array - which can be prevented if you wish with an Array.slice call beforehand.


Edit: updated the example with some ES6 fat arrows because 2015 happened and I think they look pretty... If you are concerned with backwards compatibility you can find this in the revision history.

Community
  • 1
  • 1
Emissary
  • 9,954
  • 8
  • 54
  • 65
  • This is great! Now how would you return multiple answers if there is more than one item in the array that occurs the same as another? – Crystal Nov 03 '15 at 07:51
  • 21
    If this isn't elegant code, I don't know what is. It is like an advertisement for functional programming. – Sam H. Jan 22 '16 at 22:25
  • 1
    @GoranJakovljevic Can you be more specific? I would imagine it's the [ES6 arrow functions](http://caniuse.com/#feat=arrow-functions) - have you tried the [backwards compatible example](http://jsbin.com/piqaxaqewe/edit?js,console) in the revision history? – Emissary Aug 12 '16 at 09:53
  • You are correct, its arrow functions. Yes, backwards works just fine. – Goran Jakovljevic Aug 12 '16 at 10:36
  • mode is suppose to return both elements if there are draw... `[1,2,2,3,3,4]` would be `[2,3]` – Muhammad Umer Jul 20 '17 at 22:06
  • It assumes there is a mode and that it's uniq however it's a beautiful way of using sort functionality. – Lior Elrom Feb 12 '18 at 00:36
  • 3
    Be aware, arr is going to be modified (sorted). Suggested change: `return [...arr].sort` – Daniel Pérez Rada May 19 '21 at 22:57
  • 4
    @SamH. By elegance, you must mean "succinct". Because this code is unnecessarily inefficient, repeatedly calling `.filter` on the entire array inside a loop for a time complexity of O(n * n * log(n)) for an algorithm that should be O(n). I'll reserve "elegant" for a solution that is succinct, maintainable, readable and efficient. – ggorlen May 21 '21 at 18:28
  • yeah lol my taste has changed a lot in 5 years – Sam H. May 21 '21 at 18:35
  • 2
    No problem, but you might consider deleting your comment, lest people see the +15 and are led into using this in an actual codebase. Then again, the 72 upvotes are the main issue and are hard/impossible to counteract. – ggorlen May 21 '21 at 18:37
  • 3
    This doesn't take into account the case where two strings have the same frequency ``` mode(['pear', 'apple', 'orange', 'apple', 'pear']); // pear ``` – Flavio Jul 01 '21 at 07:51
  • @Daniel Pérez Rada - yep, good spot. Alternatively `return arr.slice().sort` – rob_james Jul 26 '21 at 09:54
  • `const mode = arr => arr.slice().sort((a,b) => arr.filter(v => v===a).length - arr.filter(v => v===b).length).pop()` playaaaa Thanks! – Brian Patterson May 13 '22 at 18:34
  • But what happens if 2 values appear the same number of times? – Bill Bronson Jun 09 '22 at 11:03
45

As per George Jempty's request to have the algorithm account for ties, I propose a modified version of Matthew Flaschen's algorithm.

function modeString(array) {
  if (array.length == 0) return null;

  var modeMap = {},
    maxEl = array[0],
    maxCount = 1;

  for (var i = 0; i < array.length; i++) {
    var el = array[i];

    if (modeMap[el] == null) modeMap[el] = 1;
    else modeMap[el]++;

    if (modeMap[el] > maxCount) {
      maxEl = el;
      maxCount = modeMap[el];
    } else if (modeMap[el] == maxCount) {
      maxEl += "&" + el;
      maxCount = modeMap[el];
    }
  }
  return maxEl;
}

This will now return a string with the mode element(s) delimited by a & symbol. When the result is received it can be split on that & element and you have your mode(s).

Another option would be to return an array of mode element(s) like so:

function modeArray(array) {
  if (array.length == 0) return null;
  var modeMap = {},
    maxCount = 1,
    modes = [];

  for (var i = 0; i < array.length; i++) {
    var el = array[i];

    if (modeMap[el] == null) modeMap[el] = 1;
    else modeMap[el]++;

    if (modeMap[el] > maxCount) {
      modes = [el];
      maxCount = modeMap[el];
    } else if (modeMap[el] == maxCount) {
      modes.push(el);
      maxCount = modeMap[el];
    }
  }
  return modes;
}

In the above example you would then be able to handle the result of the function as an array of modes.

jlewkovich
  • 2,725
  • 2
  • 35
  • 49
samandmoore
  • 1,221
  • 2
  • 15
  • 23
  • 1
    In the second example (the array one); you don't need to set `modes` to `[array[0]]` as initial value. This will make sure you have duplicates in `modes`. This should do the trick `var modes = []` – vdclouis Apr 24 '15 at 10:05
  • 1
    This is great! However, when I test this with an array with two different values it returns the first item in the array twice. Not sure why that's happening... – Crystal Nov 03 '15 at 08:05
  • @xgrioux make the change that vdclouis recommends to counter this bug. i.e change [array[0]] to [ ]. – Dave Haigh Feb 16 '16 at 14:23
  • recommend changing instances of `==` to `===` to enforce strict equality – Len Joseph Jun 22 '20 at 00:00
  • Minor detail for the second example: if the array is made entirely of single items, you'll get the same array back. Should you wish to return an empty array so that you can tell your code that there's no element more frequent than others, modify the `else if (modeMap[el] == maxCount)` condition to `else if (modeMap[el] == maxCount && maxCount > 1)` – Giampaolo Ferradini Dec 03 '21 at 01:48
  • But what happens if 2 values appear the same number of times? – Bill Bronson Jun 09 '22 at 11:03
24

Based on Emissary's ES6+ answer, you could use Array.prototype.reduce to do your comparison (as opposed to sorting, popping and potentially mutating your array), which I think looks quite slick.

const mode = (myArray) =>
  myArray.reduce(
    (a,b,i,arr)=>
     (arr.filter(v=>v===a).length>=arr.filter(v=>v===b).length?a:b),
    null)

I'm defaulting to null, which won't always give you a truthful response if null is a possible option you're filtering for, maybe that could be an optional second argument

The downside, as with various other solutions, is that it doesn't handle 'draw states', but this could still be achieved with a slightly more involved reduce function.

davidsharp
  • 278
  • 2
  • 6
  • 5
    Another downside is that this is unnecessarily quadratic for what should be a linear operation. – ggorlen May 21 '21 at 18:31
16
a=['pear', 'apple', 'orange', 'apple'];
b={};
max='', maxi=0;
for(let k of a) {
  if(b[k]) b[k]++; else b[k]=1;
  if(maxi < b[k]) { max=k; maxi=b[k] }
}
Kamil Kiełczewski
  • 85,173
  • 29
  • 368
  • 345
Thinker
  • 14,234
  • 9
  • 40
  • 55
  • 1
    This is still O(n), but it unnecessarily uses two passes. – Matthew Flaschen Jun 28 '09 at 00:38
  • 4
    Since JavaScript is transmitted, it's always interesting to see small solutions. – Nosredna Jun 28 '09 at 00:49
  • Lol 2 minus for proper solution ;] I corrected unnecessarily two passes, was making it quick, but still it works and is still the shortest solution. – Thinker Jun 28 '09 at 08:44
  • 1
    each access to b takes at least log(len(b)) so O(n) might be a bit optimistic – Nicolas78 Aug 14 '10 at 12:51
  • nicolas78: If the array is small, it doesn't matter. So it depends on your project. – Thinker Aug 14 '10 at 18:19
  • 1
    -1. 4 upvotes for code that contains a syntax error and doesn't work? This code looks only at the property names, not the values. Brevity is, of itself, meaningless. Even more so if the code fails. – RobG Dec 24 '13 at 14:15
  • -1. Syntax-error: after b[k]++ is a semicolon missing. The if-else construct always executes the else part, hence can be reduced to b[k]=1; The second if-clause is executed only once for the first item in a (maxi is set to 1 and max is set to 0). So it doesn't matter what the array a contains, after execution the array b will always contain only 1s, maxi will have the value 1 and max will have the value 0. Even with syntax error fixed, this code is useless. – Alex Aug 18 '17 at 10:50
  • 2
    This pollutes the window with global variables and is unnecessarily obfuscated/unreadable. No explanation or description of how the code works or motivation for why it's a good solution was provided. – ggorlen May 21 '21 at 18:32
9

As I'm using this function as a quiz for the interviewers, I post my solution:

const highest = arr => (arr || []).reduce( ( acc, el ) => {
  acc.k[el] = acc.k[el] ? acc.k[el] + 1 : 1
  acc.max = acc.max ? acc.max < acc.k[el] ? el : acc.max : el
  return acc  
}, { k:{} }).max

const test = [0,1,2,3,4,2,3,1,0,3,2,2,2,3,3,2]
console.log(highest(test))
perusopersonale
  • 896
  • 1
  • 8
  • 18
  • This looked like the best answer here, but I'm getting cannot read property of undefined reduce.k. (line 2 in your solution). any ideas? – Brian Patterson Apr 27 '22 at 17:23
  • Nevermind, I had put the wrong variable name in the wrong spot. my bad. I think this one works pretty good, though I haven't got it working yet lol. – Brian Patterson Apr 27 '22 at 18:07
7

Trying out a declarative approach here. This solution builds an object to tally up the occurrences of each word. Then filters the object down to an array by comparing the total occurrences of each word to the highest value found in the object.

const arr = ['hello', 'world', 'hello', 'again'];

const tally = (acc, x) => { 

  if (! acc[x]) { 
    acc[x] = 1;
    return acc;
  } 

  acc[x] += 1;
  return acc;
};

const totals = arr.reduce(tally, {});

const keys = Object.keys(totals);

const values = keys.map(x => totals[x]);

const results = keys.filter(x => totals[x] === Math.max(...values));
Corey Clark
  • 116
  • 1
  • 4
  • Explain your answer please – Haris Aug 14 '16 at 14:37
  • I'd avoid calculating the max in the filter loop and remove the keys-to-values map statement. While this answer isn't the most performant, it's not as bad as filtering in the reducer and is nice and readable imho. const maxValue = Math.max(...Object.values(totals)); const results = keys.filter(x => totals[x] === maxValue); – milesaron Nov 26 '19 at 18:53
6

This solution has O(n) complexity:

function findhighestOccurenceAndNum(a) {
  let obj = {};
  let maxNum, maxVal;
  for (let v of a) {
    obj[v] = ++obj[v] || 1;
    if (maxVal === undefined || obj[v] > maxVal) {
      maxNum = v;
      maxVal = obj[v];
    }
  }
  console.log(maxNum + ' has max value = ' + maxVal);
}

findhighestOccurenceAndNum(['pear', 'apple', 'orange', 'apple']);
Michael M.
  • 10,486
  • 9
  • 18
  • 34
Gorakh Nath
  • 9,140
  • 15
  • 46
  • 68
4

Here’s the modern version using built-in maps (so it works on more than things that can be converted to unique strings):

'use strict';

const histogram = iterable => {
    const result = new Map();

    for (const x of iterable) {
        result.set(x, (result.get(x) || 0) + 1);
    }

    return result;
};

const mostCommon = iterable => {
    let maxCount = 0;
    let maxKey;

    for (const [key, count] of histogram(iterable)) {
        if (count > maxCount) {
            maxCount = count;
            maxKey = key;
        }
    }

    return maxKey;
};

console.log(mostCommon(['pear', 'apple', 'orange', 'apple']));
Ry-
  • 218,210
  • 55
  • 464
  • 476
  • If using in typescript, wrap `histogram(iterable)` with `Array.from()`: https://github.com/microsoft/TypeScript/issues/11209#issuecomment-303152976 – sMyles Apr 08 '22 at 20:45
4

For the sake of really easy to read, maintainable code I share this:

function getMaxOcurrences(arr = []) {
  let item = arr[0];
  let ocurrencesMap = {};

  for (let i in arr) {
    const current = arr[i];

    if (ocurrencesMap[current]) ocurrencesMap[current]++;
    else ocurrencesMap[current] = 1;

    if (ocurrencesMap[item] < ocurrencesMap[current]) item = current;
  }

  return { 
    item: item, 
    ocurrences: ocurrencesMap[item]
  };
}

Hope it helps someone ;)!

Eliecer Chicott
  • 541
  • 4
  • 7
3

Time for another solution:

function getMaxOccurrence(arr) {
    var o = {}, maxCount = 0, maxValue, m;
    for (var i=0, iLen=arr.length; i<iLen; i++) {
        m = arr[i];

        if (!o.hasOwnProperty(m)) {
            o[m] = 0;
        }
        ++o[m];

        if (o[m] > maxCount) {
            maxCount = o[m];
            maxValue = m;
        }
    }
    return maxValue;
}

If brevity matters (it doesn't), then:

function getMaxOccurrence(a) {
    var o = {}, mC = 0, mV, m;
    for (var i=0, iL=a.length; i<iL; i++) {
        m = a[i];
        o.hasOwnProperty(m)? ++o[m] : o[m] = 1;
        if (o[m] > mC) mC = o[m], mV = m;
    }
    return mV;
}

If non–existent members are to be avoided (e.g. sparse array), an additional hasOwnProperty test is required:

function getMaxOccurrence(a) {
    var o = {}, mC = 0, mV, m;
    for (var i=0, iL=a.length; i<iL; i++) {
        if (a.hasOwnProperty(i)) {
            m = a[i];
            o.hasOwnProperty(m)? ++o[m] : o[m] = 1;
            if (o[m] > mC) mC = o[m], mV = m;
        }
    }
    return mV;
}

getMaxOccurrence([,,,,,1,1]); // 1

Other answers here will return undefined.

RobG
  • 142,382
  • 31
  • 172
  • 209
  • 2
    @Jonah—brevity, for its own sake, is pointless and usually makes code harder to read and maintain. Of course more verbose code is not necessarily better just for being longer. But those criteria, of themselves, are obviated by much more important measures such as clarity and maintainability. – RobG Nov 05 '15 at 01:46
  • 1
    Obviously dense, cryptic brevity is never the goal. But in general, given two versions of the same code with roughly equal density, the shorter one is usually clearer and better. I'm not saying it's a _rule_, but the correlation is strong. In fact, I'd say there is no other _single_ indicator so highly correlated with readability. It's why every programmer loves to delete code. It's why most of the rewrites in Code Review are shorter than the original. – Jonah Nov 05 '15 at 05:08
3

Here is another ES6 way of doing it with O(n) complexity

const result = Object.entries(
    ['pear', 'apple', 'orange', 'apple'].reduce((previous, current) => {
        if (previous[current] === undefined) previous[current] = 1;
        else previous[current]++;
        return previous;
    }, {})).reduce((previous, current) => (current[1] >= previous[1] ? current : previous))[0];
console.log("Max value : " + result);
Rich
  • 3,928
  • 4
  • 37
  • 66
Nabil Shahid
  • 1,448
  • 8
  • 11
  • If there are duplicates this will not catch the duplicates (for example try running `['pear', 'apple', 'orange', 'orange', 'apple']`) – maxshuty Feb 08 '21 at 23:41
2

This solution can return multiple elements of an array in case of a tie. For example, an array

arr = [ 3, 4, 3, 6, 4, ];

has two mode values: 3 and 6.

Here is the solution.

function find_mode(arr) {
    var max = 0;
    var maxarr = [];
    var counter = [];
    var maxarr = [];

    arr.forEach(function(){
       counter.push(0);
    });

    for(var i = 0;i<arr.length;i++){
       for(var j=0;j<arr.length;j++){
            if(arr[i]==arr[j])counter[i]++; 
       }
    } 


    max=this.arrayMax(counter);   
  
    for(var i = 0;i<arr.length;i++){
         if(counter[i]==max)maxarr.push(arr[i]);
    }

    var unique = maxarr.filter( this.onlyUnique );
    return unique;

  };


function arrayMax(arr) {
      var len = arr.length, max = -Infinity;
      while (len--) {
              if (arr[len] > max) {
              max = arr[len];
              }
      }
  return max;
 };

 function onlyUnique(value, index, self) {
       return self.indexOf(value) === index;
 }
Let Me Tink About It
  • 15,156
  • 21
  • 98
  • 207
Reza
  • 2,896
  • 4
  • 26
  • 37
2
function mode(arr){
  return arr.reduce(function(counts,key){
    var curCount = (counts[key+''] || 0) + 1;
    counts[key+''] = curCount;
    if (curCount > counts.max) { counts.max = curCount; counts.mode = key; }
    return counts;
  }, {max:0, mode: null}).mode
}
Jonah
  • 15,806
  • 22
  • 87
  • 161
  • The problem with this solution is that the words "max" and "mode" won't count as it's part of the logic in the map... – Pablo Feb 08 '17 at 05:21
2
// O(n)
var arr = [1, 2, 3, 2, 3, 3, 5, 6];
var duplicates = {};
max = '';
maxi = 0;
arr.forEach((el) => {
    duplicates[el] = duplicates[el] + 1 || 1;
  if (maxi < duplicates[el]) {
    max = el;
    maxi = duplicates[el];
  }
});
console.log(max);
indrajeet
  • 837
  • 10
  • 17
2

Another JS solution from: https://www.w3resource.com/javascript-exercises/javascript-array-exercise-8.php

Can try this too:

let arr =['pear', 'apple', 'orange', 'apple'];

function findMostFrequent(arr) {
  let mf = 1;
  let m = 0;
  let item;

  for (let i = 0; i < arr.length; i++) {
    for (let j = i; j < arr.length; j++) {
      if (arr[i] == arr[j]) {
        m++;
        if (m > mf) {
          mf = m;
          item = arr[i];
        }
      }
    }
    m = 0;
  }

  return item;
}

findMostFrequent(arr); // apple
AugustoM
  • 405
  • 1
  • 7
  • 15
2
    const frequence = (array) =>
      array.reduce(
        (acc, item) =>
          array.filter((v) => v === acc).length >=
          array.filter((v) => v === item).length
            ? acc
            : item,
        null
      );
frequence([1, 1, 2])
Omar Borji
  • 223
  • 2
  • 9
1
var array = [1, 3, 6, 6, 6, 6, 7, 7, 12, 12, 17],
    c = {}, // counters
    s = []; // sortable array

for (var i=0; i<array.length; i++) {
    c[array[i]] = c[array[i]] || 0; // initialize
    c[array[i]]++;
} // count occurrences

for (var key in c) {
    s.push([key, c[key]])
} // build sortable array from counters

s.sort(function(a, b) {return b[1]-a[1];});

var firstMode = s[0][0];
console.log(firstMode);
David Rosson
  • 1,054
  • 1
  • 10
  • 15
1

Here is my solution to this problem but with numbers and using the new 'Set' feature. Its not very performant but i definitely had a lot of fun writing this and it does support multiple maximum values.

const mode = (arr) => [...new Set(arr)]
  .map((value) => [value, arr.filter((v) => v === value).length])
  .sort((a,b) => a[1]-b[1])
  .reverse()
  .filter((value, i, a) => a.indexOf(value) === i)
  .filter((v, i, a) => v[1] === a[0][1])
  .map((v) => v[0])

mode([1,2,3,3]) // [3]
mode([1,1,1,1,2,2,2,2,3,3,3]) // [1,2]

By the way do not use this for production this is just an illustration of how you can solve it with ES6 and Array functions only.

Anjuna5
  • 39
  • 1
  • 4
1
const mode = (str) => {
  return str
    .split(' ')
    .reduce((data, key) => {
      let counter = data.map[key] + 1 || 1
      data.map[key] = counter

      if (counter > data.counter) {
        data.counter = counter
        data.mode = key
      }

      return data
    }, {
      counter: 0,
      mode: null,
      map: {}
    })
    .mode
}

console.log(mode('the t-rex is the greatest of them all'))
Pablo
  • 2,540
  • 1
  • 18
  • 26
1

Here is my solution :-

function frequent(number){
    var count = 0;
    var sortedNumber = number.sort();
    var start = number[0], item;
    for(var i = 0 ;  i < sortedNumber.length; i++){
      if(start === sortedNumber[i] || sortedNumber[i] === sortedNumber[i+1]){
         item = sortedNumber[i]
      }
    }
    return item
  
}

   console.log( frequent(['pear', 'apple', 'orange', 'apple']))
Meheret
  • 19
  • 2
  • 4
1

Try it too, this does not take in account browser version.

function mode(arr){
var a = [],b = 0,occurrence;
    for(var i = 0; i < arr.length;i++){
    if(a[arr[i]] != undefined){
        a[arr[i]]++;
    }else{
        a[arr[i]] = 1;
    }
    }
    for(var key in a){
    if(a[key] > b){
        b = a[key];
        occurrence = key;
    }
    }
return occurrence;
}
alert(mode(['segunda','terça','terca','segunda','terça','segunda']));

Please note that this function returns latest occurence in the array when 2 or more entries appear same number of times!

msanford
  • 11,803
  • 11
  • 66
  • 93
Marcelo
  • 11
  • 2
1

With ES6, you can chain the method like this:

    function findMostFrequent(arr) {
      return arr
        .reduce((acc, cur, ind, arr) => {
          if (arr.indexOf(cur) === ind) {
            return [...acc, [cur, 1]];
          } else {
            acc[acc.indexOf(acc.find(e => e[0] === cur))] = [
              cur,
              acc[acc.indexOf(acc.find(e => e[0] === cur))][1] + 1
            ];
            return acc;
          }
        }, [])
        .sort((a, b) => b[1] - a[1])
        .filter((cur, ind, arr) => cur[1] === arr[0][1])
        .map(cur => cur[0]);
    }
    
    console.log(findMostFrequent(['pear', 'apple', 'orange', 'apple']));
    console.log(findMostFrequent(['pear', 'apple', 'orange', 'apple', 'pear']));

If two elements have the same occurrence, it will return both of them. And it works with any type of element.

Cuong Vu
  • 3,423
  • 14
  • 16
  • you should not use the variable `arr` inside a scope where that variable is already defined as a parameter. This can lead to bugs depending on which browser is used. – mesqueeb Feb 25 '20 at 08:02
  • Which `arr` is referred to by `arr.indexOf(cur)` ? The top parameter, or the one inside the reduce?? – mesqueeb Feb 25 '20 at 08:03
1

I came up with a shorter solution, but it's using lodash. Works with any data, not just strings. For objects can be used:

const mostFrequent = _.maxBy(Object.values(_.groupBy(inputArr, el => el.someUniqueProp)), arr => arr.length)[0];

This is for strings:

const mostFrequent = _.maxBy(Object.values(_.groupBy(inputArr, el => el)), arr => arr.length)[0];

Just grouping data under a certain criteria, then finding the largest group.

1

Here is my way to do it so just using .filter.

var arr = ['pear', 'apple', 'orange', 'apple'];

function dup(arrr) {
    let max = { item: 0, count: 0 };
    for (let i = 0; i < arrr.length; i++) {
        let arrOccurences = arrr.filter(item => { return item === arrr[i] }).length;
        if (arrOccurences > max.count) {
            max = { item: arrr[i], count: arrr.filter(item => { return item === arrr[i] }).length };
        }
    }
    return max.item;
}
console.log(dup(arr));
ahsan
  • 277
  • 1
  • 5
  • 18
1

Easy solution !

function mostFrequentElement(arr) {
    let res = [];
    for (let x of arr) {
        let count = 0;
        for (let i of arr) {
            if (i == x) {
                count++;
            }
        }
        res.push(count);
    }
    return arr[res.indexOf(Math.max(...res))];
}
array = [13 , 2 , 1 , 2 , 10 , 2 , 1 , 1 , 2 , 2];
let frequentElement = mostFrequentElement(array);
console.log(`The frequent element in ${array} is ${frequentElement}`);

Loop on all element and collect the Count of each element in the array that is the idea of the solution

Waleed Khaled
  • 134
  • 1
  • 5
1

Here is my solution :-

 const arr = [
2, 1, 10, 7, 10, 3, 10, 8, 7, 3, 10, 5, 4, 6, 7, 9, 2, 2, 2, 6, 3, 7, 6, 9, 8,
9, 10, 8, 8, 8, 4, 1, 9, 3, 4, 5, 8, 1, 9, 3, 2, 8, 1, 9, 6, 3, 9, 2, 3, 5, 3,
2, 7, 2, 5, 4, 5, 5, 8, 4, 6, 3, 9, 2, 3, 3, 10, 3, 3, 1, 4, 5, 4, 1, 5, 9, 6,
2, 3, 10, 9, 4, 3, 4, 5, 7, 2, 7, 2, 9, 8, 1, 8, 3, 3, 3, 3, 1, 1, 3,
];

function max(arr) {
let newObj = {};

arr.forEach((d, i) => {
    if (newObj[d] != undefined) {
        ++newObj[d];
    } else {
        newObj[d] = 0;
    }
});
let nwres = {};
for (let maxItem in newObj) {
    if (newObj[maxItem] == Math.max(...Object.values(newObj))) {
        nwres[maxItem] = newObj[maxItem];
    }
}
return nwres;
}


console.log(max(arr));
KARTHIKEYAN.A
  • 18,210
  • 6
  • 124
  • 133
0
var mode = 0;
var c = 0;
var num = new Array();
var value = 0;
var greatest = 0;
var ct = 0;

Note: ct is the length of the array.

function getMode()
{
    for (var i = 0; i < ct; i++)
    {
        value = num[i];
        if (i != ct)
        {
            while (value == num[i + 1])
            {
                c = c + 1;
                i = i + 1;
            }
        }
        if (c > greatest)
        {
            greatest = c;
            mode = value;
        }
        c = 0;
    }
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
0

I guess you have two approaches. Both of which have advantages.

Sort then Count or Loop through and use a hash table to do the counting for you.

The hashtable is nice because once you are done processing you also have all the distinct elements. If you had millions of items though, the hash table could end up using a lot of memory if the duplication rate is low. The sort, then count approach would have a much more controllable memory footprint.

Steve Sheldon
  • 6,421
  • 3
  • 31
  • 35
0

You can try this:

 // using splice()   
 // get the element with the highest occurence in an array
    function mc(a) {
      var us = [], l;
      // find all the unique elements in the array
      a.forEach(function (v) {
        if (us.indexOf(v) === -1) {
          us.push(v);
        }
      });
      l = us.length;
      while (true) {
        for (var i = 0; i < l; i ++) {
          if (a.indexOf(us[i]) === -1) {
            continue;
          } else if (a.indexOf(us[i]) != -1 && a.length > 1) {
            // just delete it once at a time
            a.splice(a.indexOf(us[i]), 1);
          } else {
            // default to last one
            return a[0];
          }
        }
      }
    }

// using string.match method
function su(a) {
    var s = a.join(),
            uelms = [],
            r = {},
            l,
            i,
            m;

    a.forEach(function (v) {
        if (uelms.indexOf(v) === -1) {
            uelms.push(v);
        }
    });

    l = uelms.length;

    // use match to calculate occurance times
    for (i = 0; i < l; i ++) {
        r[uelms[i]] = s.match(new RegExp(uelms[i], 'g')).length;
    }

    m = uelms[0];
    for (var p in r) {
        if (r[p] > r[m]) {
            m = p;
        } else {
            continue;
        }
    }

    return m;
}
void4096
  • 1
  • 4
0

You could solve it in O(n) complexity

var arr = [1,3,54,56,6,6,1,6];
var obj = {};

/* first convert the array in to object with unique elements and number of times each element is repeated */
for(var i = 0; i < arr.length; i++)
{
   var x = arr[i];
   if(!obj[x])
     obj[x] = 1;
   else 
     obj[x]++;
}

console.log(obj);//just for reference

/* now traverse the object to get the element */
var index = 0;
var max = 0;

for(var obIndex in obj)
{
  if(obj[obIndex] > max)
  {
    max = obj[obIndex];
    index = obIndex;
  }
}
console.log(index+" got maximum time repeated, with "+ max +" times" );

Just copy and paste in chrome console to run the above code.

Sandeep Gantait
  • 837
  • 8
  • 9
0

This function is generic function for every type of info. It counts the occurrence of the elements and then returns array with maximum occurring elements.

function mode () {
  var arr = [].slice.call(arguments);
  if ((args.length == 1) && (typeof args[0] === "object")) {
    args = args[0].mode();
  }

  var obj = {};
  for(var i = 0; i < arr.length; i++) {
    if(obj[arr[i]] === undefined) obj[arr[i]] = 1;
    else obj[arr[i]]++;
  }

  var max = 0;
  for (w in obj) {
    if (obj[w] > max) max = obj[w];
  }

  ret_val = [];
  for (w in obj) {
    if (obj[w] == max) ret_val.push(w);
  }

  return ret_val;
}
0
function mode(){
  var input = $("input").val().split(",");
  var mode = [];
  var m = [];
  var p = [];
    for(var x = 0;x< input.length;x++){
      if(m.indexOf(input[x])==-1){
        m[m.length]=input[x];
    }}
  for(var x = 0; x< m.length;x++){
    p[x]=0;
    for(var y = 0; y<input.length;y++){
      if(input[y]==m[x]){
      p[x]++; 
 }}}
 for(var x = 0;x< p.length;x++){
   if(p[x] ==(Math.max.apply(null, p))){
     mode.push(m[x]);
 }} 
$("#output").text(mode);}
0
function mode(array){
    var set = Array.from(new Set(array));
    var counts = set.map(a=>array.filter(b=>b==a).length);
    var indices = counts.map((a,b)=>Math.max(...counts)===a?b:0).filter(b=>b!==0);
    var mode = indices.map(a=>set[a]);
    return mode;
}
ido klein
  • 137
  • 2
  • 11
0

Here is my way. I try to group data fist.

const _ = require("underscore")

var test  = [ 1, 1, 2, 1 ];
var groupResult = _.groupBy(test, (e)=> e);

The groupResult should be

{
  1: [1, 1, 1]
  2: [2] 
}

Then find the property which has the longest array

function findMax(groupResult){
   var maxArr = []
   var max;
   for(var item in groupResult){
     if(!max) { 
        max = { value:item, count: groupResult[item].length } ; 
        maxArr.push(max); 
        continue;
     }
     if(max.count < groupResult[item].length){ 
        maxArr = [];
        max = { value:item, count: groupResult[item].length }
        maxArr.push(max)
     } else if(max === groupResult[item].length)
        maxArr.push({ value:item, count: groupResult[item].length })
   }
   return maxArr;
}

The complete code looks like

const _ = require("underscore")

var test  = [ 1, 1, 2, 1 ];
var groupResult= _.groupBy(test, (e)=> e);
console.log(findMax(groupResult)[0].value);

function findMax(groupResult){
   var maxArr = []
   var max;
   for(var item in groupResult){
     if(!max) { 
        max = { value:item, count: groupResult[item].length } ; 
        maxArr.push(max); 
        continue;
     }
     if(max.count < groupResult[item].length){ 
        maxArr = [];
        max = { value:item, count: groupResult[item].length }
        maxArr.push(max)
     } else if(max === groupResult[item].length)
        maxArr.push({ value:item, count: groupResult[item].length })
   }
   return maxArr;
}
Andy Lai
  • 1,714
  • 1
  • 14
  • 17
0
var cats = ['Tom','Fluffy','Tom','Bella','Chloe','Tom','Chloe'];
var counts = {};
var compare = 0;
var mostFrequent;
(function(array){
   for(var i = 0, len = array.length; i < len; i++){
       var word = array[i];

       if(counts[word] === undefined){
           counts[word] = 1;
       }else{
           counts[word] = counts[word] + 1;
       }
       if(counts[word] > compare){
             compare = counts[word];
             mostFrequent = cats[i];
       }
    }
  return mostFrequent;
})(cats);
Rubin bhandari
  • 1,873
  • 15
  • 20
0

Can try :

var arr = [10,3,4,5,3,4,3,8,3,6,3,5,1];
var temp = {};

for(let i=0;i<arr.length;i++){
    if(temp[arr[i]]==undefined){
       temp[arr[i]]=1;
    }else{
        temp[arr[i]]+=1;
    }
}

var max=0, maxEle;

for(const i in temp){
    if(temp[i]>max){
        max = temp[i];
        maxEle=i;
    }
}

console.log(`most occurred element is ${maxEle} and number of times is ${max}`);`
jaibalaji
  • 3,159
  • 2
  • 15
  • 28
0

There are a lot of answers already but just want to share with you what I came up with :) Can't say this solution counts on any edge case but anyway )

const getMostFrequentElement = ( arr ) => {
  const counterSymbolKey = 'counter'
  const mostFrequentSymbolKey = 'mostFrequentKey'

  const result = arr.reduce( ( acc, cur ) => {
    acc[ cur ] = acc[ cur ] ? acc[ cur ] + 1 : 1

    if ( acc[ cur ] > acc[ Symbol.for( counterSymbolKey ) ] ) {
      acc[ Symbol.for( mostFrequentSymbolKey ) ] = cur
      acc[ Symbol.for( counterSymbolKey ) ] = acc[ cur ]
    }

    return acc
  }, {
    [ Symbol.for( mostFrequentSymbolKey ) ]: null,
    [ Symbol.for( counterSymbolKey ) ]: 0
  } )

  return result[ Symbol.for( mostFrequentSymbolKey ) ]
}

Hope it will be helpful for someone )

Vladislav Mykhailenko
  • 1,961
  • 1
  • 9
  • 5
0

//const arr = [1, 2, 4, 3, 5, 1, 2, 3, 3];
const arr = ['pear', 'apple', 'orange', 'apple'];

// init max occurance element
let maxOcc = {'element': null, occured: 0};

// to find occurances
const res = arr.reduce((acc, el) => {
    acc[el] = acc[el] ? acc[el]+1 : 1;
    if(acc[el]> maxOcc.occured){
        maxOcc = { 'element': el, occured: acc[el] };
    }
    return acc;
}, {});

console.log(maxOcc);
navnath
  • 3,548
  • 1
  • 11
  • 19
0
function getData(arr){
  let obj = {}
  let maxElementCount = 0
  let maxEle = ''
  for(let i = 0 ;i<arr.length;i++){
    if(!obj[arr[i]]){
        obj[arr[i]] = 1
    }else{
        obj[arr[i]] += 1
      if(maxElementCount < obj[arr[i]]){
        maxElementCount = obj[arr[i]]
        maxEle = arr[i]
      }
    }
  }
  console.log(maxElementCount, maxEle)
  return obj
}

You can use this simple method to get max count of element

0

const data = ['x','y','x','z',5,2,4,5,2,3,2,'x', { x: 1 }, (x) => x];

function getModeData(data) {
  return data.reduce((a,c) => {
    if(typeof a[c] === "undefined") {
      a[c] = 1;
    } else {
      a[c]++;
    }
    if(
      typeof a.mode === "undefined" ||
      (typeof a.mode !== "undefined") && a.mode.occurrences < a[c]
    ) {
      a.mode = {
        elem: c,
        occurrences: a[c]
      }
    }
    return a;
  }, { mode: undefined });
}

const { mode: { elem, occurrences }, ...totals } = getModeData(data);

console.log(`The mode is ${elem} with ${occurrences} occurrences`);

console.log('The totals are:');
console.log(totals)
0

I saw that a lot of answers had a lot of recursions through the array, which I wanted to avoid. In addition to this, I wanted to have Typescript checking the result and inferring the right type.

So this is my version:

function findhighestOccurence<Type extends string | number>(myArray: Type[]) {
    const countOccorrencies = myArray.reduce<{ [key in Type]: number }>(
        (acc, curr) => ({ ...acc, [curr]: acc[curr] ? acc[curr] + 1 : 1 }),
        {} as { [K in Type]: number }
    )

    return (Object.entries(countOccorrencies) as [Type, number][]).reduce<{
        values: Type[] // there might be multiple "highest occurences" values
        occurrences: number // how many times it has/they have occurred
    }>(
        (acc, [value, occurrences]) => {
            // new highest occurrence
            if (occurrences > acc.occurrences)
                return {
                    ...acc,
                    occurrences: occurrences,
                    values: [value],
                }
            // new value with same highest amount of occurrences
            else if (occurrences === acc.occurrences)
                return { ...acc, values: [...acc.values, value] }
            return acc
        },
        { values: [], occurrences: 0 }
    )
}

Succint version:

function findhighestOccurenceShort<T extends string | number>(myArray: T[]) {
    return (
        Object.entries(
            myArray.reduce<{ [key in T]: number }>(
                (acc, cur) => ({ ...acc, [cur]: acc[cur] ? acc[cur] + 1 : 1 }),
                {} as { [K in T]: number }
            )
        ) as [T, number][]
    ).reduce<{ val: T[]; occ: number }>(
        (acc, [val, occ]) =>
            occ > acc.occ
                ? { occ, val: [val] }
                : occ === acc.occ
                ? { occ, val: [...acc.val, val] }
                : acc,
        { val: [], occ: 0 }
    )
}
Francesco Bianchi
  • 772
  • 1
  • 4
  • 13