Get the element with the highest occurrence in an array

Viewed 156385

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.

41 Answers

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;
}
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] }
}

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

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 ;)!

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']));

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);

This solution has O(n) complexity

function findhighestOccurenceAndNum(a){
    let obj={};
    let maxNum;
    let 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);
}

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
    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])

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.

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!

// 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);

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.

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));

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));

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

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.

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}`);`

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 )

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

//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);

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

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)

Related