3

I have wounder`d for a while about how to get mode in array. That elements that are the same in array would be put together. For ex. [Alex, Steven, Georg, Alice, Alex, Georg]; return would be: Alex: 2, Steven: 1, Georg: 2, Alice:1;

I wrote the code but it works only for numbers from 1 to 10. And for sure there is a better way.

(I don`t think you need my code but will paste it anyway.)

var mode = function (data){
            var result1 = data.filter(function (verde) {return verde === 1});
            var result2 = data.filter(function (verde) {return verde === 2});
            var result3 = data.filter(function (verde) {return verde === 3});
            var result4 = data.filter(function (verde) {return verde === 4});
            var result5 = data.filter(function (verde) {return verde === 5});
            var result6 = data.filter(function (verde) {return verde === 6});
            var result7 = data.filter(function (verde) {return verde === 7});
            var result8 = data.filter(function (verde) {return verde === 8});
            var result9 = data.filter(function (verde) {return verde === 9});

            var nyadata = [result1.length, result2.length,
                           result3.length, result4.length,
                           result5.length, result6.length,
                           result7.length, result8.length,
                           result9.length];

            var nyarreymax = Math.max.apply(Math, nyadata);

            if (nyarreymax === result1.length){return 1;}
            if (nyarreymax === result2.length){return 2;}
            if (nyarreymax === result3.length){return 3;}
            if (nyarreymax === result4.length){return 4;}
            if (nyarreymax === result5.length){return 5;}
            if (nyarreymax === result6.length){return 6;}
            if (nyarreymax === result7.length){return 7;}
            if (nyarreymax === result8.length){return 8;}
            if (nyarreymax === result9.length){return 9;} 
            else { return  false;}

Hope you can help me to know code that works generally for strings and all integers.

mvw
  • 5,075
  • 1
  • 28
  • 34
Dovydas
  • 213
  • 1
  • 2
  • 6
  • I'm a little uncertain on what you're asking, are you looking for the iteration count of items in an array ? If so; this might help : http://stackoverflow.com/questions/19395257/how-to-count-duplicate-value-in-an-array-in-javascript – Pogrindis Sep 25 '15 at 16:36
  • That code seems to lack a closing curly brace `}`. – mvw Sep 25 '15 at 16:42

8 Answers8

2

I'm a beginner at js myself and was looking for this same solution not long ago. Here's one I found that should be what you're looking for:

function findMode(arr) {
    var map = {};
    for (var i = 0; i < arr.length; i++) {
        if (map[arr[i]] === undefined) {
            map[arr[i]] = 0;
        }
        map[arr[i]] += 1;
    }
    var greatestFreq = 0;
    var mode;
    for (var prop in map) {
        if (map[prop] > greatestFreq) {
            greatestFreq = map[prop];
            mode = prop;
        }
    }
    return mode;
}
Andreas
  • 21,535
  • 7
  • 47
  • 56
Derek Huang
  • 36
  • 1
  • 3
1

You can try this using reduce() , see your console that shows value with counts.

Demo http://jsfiddle.net/ak69f/

var array_elements = ['Alex', 'Steven', 'Georg', 'Alice', 'Alex', 'Georg'];

var result = array_elements.reduce(function(p, c){
    if (c in p) {
       p[c]++;
    } else {
        p[c]=1;
    }
    return p;
}, []);

console.log(result);
A l w a y s S u n n y
  • 36,497
  • 8
  • 60
  • 103
1

Here's a simple recursive solution, which seems to be the fastest of the four answers as you can see here: http://jsperf.com/array-mode.

var a = ["Alex", "Steven", "Georg", "Alice", "Alex", "Georg"];

function getMode(a, result) {
  result = result || {};
  
  if (a.length === 0){
    return result;
  }
  
  var head = a.shift();
  if (result[head]){
    result[head]++;
  }
  else{
    result[head] = 1;
  }
  return getMode(a, result);
}

console.log(getMode(a));
Dave
  • 10,748
  • 3
  • 43
  • 54
0

First, define a new array that will hold your results. Iterate through your names array. Inside of each loop, iterate through the results array. If the current name in your names array exists within the results array, change the value.

For example, if your names array is on the second "Alex", and you iterate through the results array and find that "Alex:1" already exists, change the value to "Alex:2" (you will have to do a little bit of string parsing for that).

If the name does not exist already, add it to the end as ":1"

Then if you want to return the mode, you will have to write another loop that finds the maximum occurrence. Have a variable that keeps track of the array position of the name with the highest number (let's say it's called maxIndex). For each item in the array, compare it to the value of the array at maxIndex. If it's higher, reset maxIndex to the current index. If it's equal to or less than, move onto the next item of the array.

I know that was very wordy, so let me know if you have any questions.

amklose
  • 1,143
  • 8
  • 15
  • Better to use an object to store the results since you won't have to loop through it to find existing matches. – Dave Sep 25 '15 at 16:53
  • Fair enough, but I was under the impression the OP wanted the results as an array of strings. Your method looks much cleaner though. – amklose Sep 25 '15 at 17:00
0

An alternative approach to this is to create a function that takes in your array, assigns each unique array value to an object property and if it already exists, increase the object properties value by one, like so;

function countArray(array){
        var results = {};

        for(var x = 0; x < array.length; x++){

            if(results[array[x]] == undefined){
                results[array[x]] = 1;
            }else{
                results[array[x]] += 1;
            }
        }

        return results;
    }

    var checkArray = countArray(['alex', 'george', 'steve', 'alex']);

    console.log(checkArray); 
    // outputs "Object {alex: 2, george: 1, steve: 1}"

Then you could access the results as needed by calling

console.log(checkArray.alex); // outputs 2
Lewis
  • 3,479
  • 25
  • 40
0
var numbers = [1,2,2,3,4,5];
var counts = numbers.reduce((counts, e) => { counts[e] = counts[e] ? counts[e] + 1 : 1; return counts; }, {});
var mode = Object.keys(counts).reduce((a, b) => (counts[a] > counts[b] ? a : b ));
console.log(mode);

Reduce function can help a lot in aggregations.

Abhilash
  • 2,026
  • 17
  • 21
0

The way I have found is very similar to the accepted answer however I thought I would add that if no items repeat, or no single item repeats the most, there is no mode, so my function checks that and returns null if that's the case.

function calcMode(data) {
  let counts = {};
  data.forEach((d) => {
    if (counts[d] === undefined) {
      counts[d] = 0;
    }
    counts[d] += 1;
  });
  let mode,
    max = 0,
    repeats = 0;
  Object.keys(counts).forEach((k) => {
    if (counts[k] > max) {
      max = counts[k];
      mode = k;
      repeats = 0;
    } else if (counts[k] == max) repeats += 1;
  });
  if (!repeats) {
    if (isNaN(mode)) return mode;
    else return +mode;
  } else return null;
}
0

This was my approach, I tried a "functional" style using reduce. It also supports multimodes, so it will return an array of modes.

export function mode(vector) {
if (vector.length === 0) return undefined

 return (vector.reduce((accu, curr) => {
    const freqsMap = accu.freqsMap
    freqsMap.set(curr, (freqsMap.get(curr) || 0) + 1)

    const maxCount = freqsMap.get(curr) > accu.maxCount
        ? freqsMap.get(curr)
        : accu.maxCount
    const modes = freqsMap.get(curr) === accu.maxCount
        ? [...accu.modes, curr]
        : freqsMap.get(curr) > accu.maxCount
            ? [curr]
            : accu.modes

    return { freqsMap, maxCount, modes }
 }, { freqsMap: new Map(), maxCount: 1, modes: []})).modes
}
diegocl02
  • 2,688
  • 2
  • 9
  • 10