Shrey Gupta Shrey Gupta - 11 months ago 38
Javascript Question

Efficiently find the number of occurrences a given value has in an array

I have an array with repeating values. I would like to find the number of occurrences for any given value.

For example, if I have an array defined as so:

var dataset = [2,2,4,2,6,4,7,8];
, I want to find the number of occurrences of a certain value in the array. That is, the program should show that if I have 3 occurrences of the value
, 1 occurrence of the value
, and so on.

What's the most efficient way to do this?

Answer Source

reduce is more appropriate here than filter as it doesn't build a temporary array just for counting.

var dataset = [2,2,4,2,6,4,7,8];
var search = 2;
var count = dataset.reduce(function(n, val) {
    return n + (val === search);
}, 0);

Note that it's easy to extend that to use a custom matching predicate, for example, to count objects that have a specific property:

people = [
    {name: 'Mary', gender: 'girl'},
    {name: 'Paul', gender: 'boy'},
    {name: 'John', gender: 'boy'},
    {name: 'Lisa', gender: 'girl'},
    {name: 'Bill', gender: 'boy'},
    {name: 'Maklatura', gender: 'girl'}

var numBoys = people.reduce(function(n, person) {
    return n + (person.gender == 'boy');
}, 0);

Counting all items, that is, making an object like {x:count of xs} is complicated in javascript, because object keys can only be strings, so you can't reliably count an array with mixed types. Still, the following simple solution will work well in most cases:

count = function(ary, classifier) {
    return ary.reduce(function(counter, item) {
        var p = (classifier || String)(item);
        counter[p] = counter.hasOwnProperty(p) ? counter[p] + 1 : 1;
        return counter;
    }, {})

If you don't provide a classifier this simply counts different elements:

> count([1,2,2,2,3,1])
 "1": 2,
 "2": 3,
 "3": 1

With a classifier you group elements by specific property:

> countByGender = count(people, function(item) { return item.gender })
 "girl": 3,
 "boy": 3