299

I have an array:

[1, 2, 3, 5, 2, 8, 9, 2]

I would like to know how many 2s are in the array.

What is the most elegant way to do it in JavaScript without looping with for loop?

Alexander Abakumov
  • 13,617
  • 16
  • 88
  • 129
Leem
  • 17,220
  • 36
  • 109
  • 159

27 Answers27

484

[this answer is a bit dated: read the edits, in the notion of 'equal' in javascript is ambiguous]

Say hello to your friends: map and filter and reduce and forEach and every etc.

(I only occasionally write for-loops in javascript, because of block-level scoping is missing, so you have to use a function as the body of the loop anyway if you need to capture or clone your iteration index or value. For-loops are more efficient generally, but sometimes you need a closure.)

The most readable way:

[....].filter(x => x==2).length

(We could have written .filter(function(x){return x==2}).length instead)

The following is more space-efficient (O(1) rather than O(N)), but I'm not sure how much of a benefit/penalty you might pay in terms of time (not more than a constant factor since you visit each element exactly once):

[....].reduce((total,x) => (x==2 ? total+1 : total), 0)

or as a commenter kindly pointed out:

[....].reduce((total,x) => total+(x==2), 0)

(If you need to optimize this particular piece of code, a for loop might be faster on some browsers... you can test things on jsperf.com.)


You can then be elegant and turn it into a prototype function:

[1, 2, 3, 5, 2, 8, 9, 2].count(2)

Like this:

Object.defineProperties(Array.prototype, {
    count: {
        value: function(value) {
            return this.filter(x => x==value).length;
        }
    }
});

You can also stick the regular old for-loop technique (see other answers) inside the above property definition (again, that would likely be much faster).


2017 edit:

Whoops, this answer has gotten more popular than the correct answer. Actually, just use the accepted answer. While this answer may be cute, the js compilers probably don't (or can't due to spec) optimize such cases. So you should really write a simple for loop:

Object.defineProperties(Array.prototype, {
    count: {
        value: function(query) {
            /* 
               Counts number of occurrences of query in array, an integer >= 0 
               Uses the javascript == notion of equality.
            */
            var count = 0;
            for(let i=0; i<this.length; i++)
                if (this[i]==query)
                    count++;
            return count;
        }
    }
});

You could define a version .countStrictEq(...) which used the === notion of equality. The notion of equality may be important to what you're doing! (for example [1,10,3,'10'].count(10)==2, because numbers like '4'==4 in javascript... hence calling it .countEq or .countNonstrict stresses it uses the == operator.)

Caveat: Defining a common name on the prototype should be done with care. It is fine if you control your code, but bad if everyone wants to declare their own [].count function, especially if they behave differently. You may ask yourself "but .count(query) surely sounds quite perfect and canonical"... but consider perhaps you could do something like [].count(x=> someExpr of x). In that case you define functions like countIn(query, container) (under myModuleName.countIn), or something, or [].myModuleName_count().

Also consider using your own multiset data structure (e.g. like python's 'collections.Counter') to avoid having to do the counting in the first place. This works for exact matches of the form [].filter(x=> x==???).length (worst case O(N) down to O(1)), and modified will speed up queries of the form [].filter(filterFunction).length (roughly by a factor of #total/#duplicates).

class Multiset extends Map {
    constructor(...args) {
        super(...args);
    }
    add(elem) {
        if (!this.has(elem))
            this.set(elem, 1);
        else
            this.set(elem, this.get(elem)+1);
    }
    remove(elem) {
        var count = this.has(elem) ? this.get(elem) : 0;
        if (count>1) {
            this.set(elem, count-1);
        } else if (count==1) {
            this.delete(elem);
        } else if (count==0)
            throw `tried to remove element ${elem} of type ${typeof elem} from Multiset, but does not exist in Multiset (count is 0 and cannot go negative)`;
            // alternatively do nothing {}
    }
}

Demo:

> counts = new Multiset([['a',1],['b',3]])
Map(2) {"a" => 1, "b" => 3}

> counts.add('c')
> counts
Map(3) {"a" => 1, "b" => 3, "c" => 1}

> counts.remove('a')
> counts
Map(2) {"b" => 3, "c" => 1}

> counts.remove('a')
Uncaught tried to remove element a of type string from Multiset, but does not exist in Multiset (count is 0 and cannot go negative)

sidenote: Though, if you still wanted the functional-programming way (or a throwaway one-liner without overriding Array.prototype), you could write it more tersely nowadays as [...].filter(x => x==2).length. If you care about performance, note that while this is asymptotically the same performance as the for-loop (O(N) time), it may require O(N) extra memory (instead of O(1) memory) because it will almost certainly generate an intermediate array and then count the elements of that intermediate array.

ninjagecko
  • 88,546
  • 24
  • 137
  • 145
  • 1
    This is a good FP solution, the only "problem" (irrelevant for most cases) it creates an intermediate array. – tokland May 25 '11 at 08:35
  • 1
    @tokland: If that is a concern, you can do `array.reduce(function(total,x){return x==value? : total+1 : total}, 0)` – ninjagecko Sep 11 '12 at 14:57
  • 1
    @ninjagecko Shouldn't there only be one colon in the ternary operator? `[...].reduce(function(total,x){return x==2 ? total+1 : total}, 0)` – indigo Mar 11 '14 at 19:23
  • 3
    @tokland Maybe the filter will **not** create an intermediate array. A good optimizing compiler can easily recognize that only the length of the array is used. Maybe none of the current JS compilers are smart enough to do this, but that is not important. As Fowler says, "If something hurts, then do more of it". It is short-sighted to avoid compiler deficiencies by writing poor code. If the compiler sucks, fix the compiler. https://mlafeldt.github.io/blog/if-it-hurts-do-it-more-often/ – John Henckel Sep 21 '17 at 14:37
  • 1
    I would consider this an optimal 2017 solution: `const count = (list) => list.filter((x) => x == 2).length`. Then use it by calling `count(list)` where list is an array of numbers. You can also do `const count = (list) => list.filter((x) => x.someProp === 'crazyValue').length` to count instances of crazyValue in the array of objects. Note, it is an exact match for the property. – agm1984 Sep 30 '17 at 07:43
  • You could improve it by adding a search term parameter: `const count = (list, searchTerm) => list.filter((x) => x === searchTerm).length` Then: `count(arrayName, 'something to exact match')` – agm1984 Sep 30 '17 at 07:50
  • const tot = [1,2,3,4,5,2].reduce( (prev,curr) => prev += curr == 2, 0) or let tot = 0; [1,2,2,3,4,5].forEach( x => tot += x==2 ); – Drout Aug 15 '22 at 23:25
146

Modern JavaScript:

Note that you should always use triple equals === when doing comparison in JavaScript (JS). The triple equals make sure, that JS comparison behaves like double equals == in other languages (there is one exception, see below). The following solution shows how to solve this the functional way, which will ensure that you will never have out of bounds error:

// Let has local scope
let array = [1, 2, 3, 5, 2, 8, 9, 2]

// Functional filter with an Arrow function
// Filter all elements equal to 2 and return the length (count)
array.filter(x => x === 2).length  // -> 3

The following anonymous Arrow function (lambda function) in JavaScript:

(x) => {
   const k = 2
   return k * x
}

may be simplified to this concise form for a single input:

x => 2 * x

where the return is implied.

Always use triple equals: === for comparison in JS, with the exception of when checking for nullability: if (something == null) {} as it includes a check for undefined, if you only use double equals as in this case.

Sverrisson
  • 17,970
  • 5
  • 66
  • 62
  • Is the filter function more performant than using the es6 for of loop? – Niklas Feb 18 '20 at 16:06
  • 1
    @Niklas, I think it's the same (as both have to check all elements, O(N)), but, I guess it's browser dependent and also on the number of elements and computer as to what fits in cache memory. So, I guess the answer is: "It's complex" :) – Sverrisson Feb 18 '20 at 23:08
  • I would guess reduce is more efficient than filter, because with filter you create a whole new array just to get its length – Kip Jan 21 '22 at 00:21
  • @Kip this is about readability and filter clearly tells everyone reading the code the intentions of it. I would not assume anything about efficiency, as the complier may optimise when it sees the result not being used for anything else but counting. Premature optimisation is less important than readability, in my opinion. – Sverrisson Jan 22 '22 at 13:17
  • @Sverrisson this is exactly the type of problem that reduce is designed to solve. even if reduce is harder to read (i don't really agree there), putting `// count the number of elements equal to two` on the line before makes either filter or reduce more readable – Kip Jan 23 '22 at 15:27
  • @Kip I agree that this can be solved with `reduce` and one of the answers below does that. But when I answered this, I was trying to write it with someone learning JavaScript in mind and thus, decided on the `filter` function. – Sverrisson Jan 24 '22 at 16:05
117

Very simple:

var count = 0;
for(var i = 0; i < array.length; ++i){
    if(array[i] == 2)
        count++;
}
Thor Jacobsen
  • 8,621
  • 2
  • 27
  • 26
  • 82
    No, what I mean is without looping with "for" – Leem May 25 '11 at 07:42
  • 1
    @Leem: While there are ways to do this without using an iterative loop, they're far more expensive (i.e. using strings and regex to calculate the number of matches) and therefore useless in real world applications. – Demian Brecht May 25 '11 at 07:49
  • 18
    @Leem: Why is looping bad? There is always looping at some point. Obviously you would create a function that hides the loop. These *"I don't want to use the right tool for the job"* -requests never made much sense to me. And we can argue what is most elegant. E.g. for me, making a function call per element to just to compare it to a value is not elegant. – Felix Kling May 25 '11 at 08:33
  • 2
    for laughs: alert(eval('('+my_array.join('==2)+(')+'==2)')) https://jsfiddle.net/gaby_de_wilde/gujbmych/ – user40521 Jan 07 '16 at 19:29
  • 58
    The OP probably thinks looping is bad because it is 5 lines of code and requires mutable state. A developer who comes to read that later will have to spend some time to check what it does, and lose focus from their task. An abstraction is far superior: [`const count = countItems(array, 2);`](http://stackoverflow.com/a/6125774/99777) and the implementation details can be argued inside. – joeytwiddle Jul 14 '16 at 05:37
  • 4
    This isn't the right answer because the question clearly ask for not using loops. Check my solution that makes no use of loops. https://stackoverflow.com/a/44743436/8211014 – Luis Orantes Apr 02 '18 at 01:38
  • 3
    JS .reduce() still uses a loop. The only difference there is that the loop is hidden in the reduce source code instead of your own function. – Kyle Alm Jan 13 '21 at 15:41
81

2017: If someone is still interested in the question, my solution is the following:

const arrayToCount = [1, 2, 3, 5, 2, 8, 9, 2];
const result = arrayToCount.filter(i => i === 2).length;
console.log('number of the found elements: ' + result);
Raild
  • 923
  • 7
  • 12
19

Here is an ES2017+ way to get the counts for all array items in O(N):

const arr = [1, 2, 3, 5, 2, 8, 9, 2];
const counts = {};

arr.forEach((el) => {
  counts[el] = counts[el] ? (counts[el] + 1) : 1;
});

You can also optionally sort the output:

const countsSorted = Object.entries(counts).sort(([_, a], [__, b]) => a - b);

console.log(countsSorted) for your example array:

[
  [ '2', 3 ],
  [ '1', 1 ],
  [ '3', 1 ],
  [ '5', 1 ],
  [ '8', 1 ],
  [ '9', 1 ]
]
General Grievance
  • 4,555
  • 31
  • 31
  • 45
  • `counts.hasOwnProperty(el)` is safer than `counts[el]` because, while not applicable here, zero is treated as false, so if `counts[el] = 0`, then `counts[el] == false` – Edwarric Dec 03 '21 at 13:31
12

If you are using lodash or underscore the _.countBy method will provide an object of aggregate totals keyed by each value in the array. You can turn this into a one-liner if you only need to count one value:

_.countBy(['foo', 'foo', 'bar'])['foo']; // 2

This also works fine on arrays of numbers. The one-liner for your example would be:

_.countBy([1, 2, 3, 5, 2, 8, 9, 2])[2]; // 3
Coleman
  • 631
  • 5
  • 13
  • 7
    Huge overkill. As it creates counters for all unique elements. Wasted storage and time. – metalim Dec 04 '17 at 07:38
  • 1
    Keep in mind that lodash always adds to your bundle size, often quite significantly. For something as simple as counting array items I wouldn't reach for lodash. – Yanick J. Steinbeck Nov 12 '21 at 21:29
5

Weirdest way I can think of doing this is:

(a.length-(' '+a.join(' ')+' ').split(' '+n+' ').join(' ').match(/ /g).length)+1

Where:

  • a is the array
  • n is the number to count in the array

My suggestion, use a while or for loop ;-)

Gary Green
  • 22,045
  • 6
  • 49
  • 75
4

Not using a loop usually means handing the process over to some method that does use a loop.

Here is a way our loop hating coder can satisfy his loathing, at a price:

var a=[1, 2, 3, 5, 2, 8, 9, 2];

alert(String(a).replace(/[^2]+/g,'').length);


/*  returned value: (Number)
3
*/

You can also repeatedly call indexOf, if it is available as an array method, and move the search pointer each time.

This does not create a new array, and the loop is faster than a forEach or filter.

It could make a difference if you have a million members to look at.

function countItems(arr, what){
    var count= 0, i;
    while((i= arr.indexOf(what, i))!= -1){
        ++count;
        ++i;
    }
    return count
}

countItems(a,2)

/*  returned value: (Number)
3
*/
kennebec
  • 102,654
  • 32
  • 106
  • 127
3

Really, why would you need map or filter for this? reduce was "born" for these kind of operations:

[1, 2, 3, 5, 2, 8, 9, 2].reduce( (count,2)=>count+(item==val), 0);

that's it! (if item==val in each iteration, then 1 will be added to the accumulator count, as true will resolve to 1).

As a function:

function countInArray(arr, val) {
   return arr.reduce((count,item)=>count+(item==val),0)
}

Or, go ahead and extend your arrays:

Array.prototype.count = function(val) {
   return this.reduce((count,item)=>count+(item==val),0)
}
Yuval A.
  • 5,849
  • 11
  • 51
  • 63
3

I'm a begin fan of js array's reduce function.

const myArray =[1, 2, 3, 5, 2, 8, 9, 2];
const count = myArray.reduce((count, num) => num === 2 ? count + 1 : count, 0)

In fact if you really want to get fancy you can create a count function on the Array prototype. Then you can reuse it.

Array.prototype.count = function(filterMethod) {
  return this.reduce((count, item) => filterMethod(item)? count + 1 : count, 0);
} 

Then do

const myArray =[1, 2, 3, 5, 2, 8, 9, 2]
const count = myArray.count(x => x==2)
Scott Blanch
  • 178
  • 1
  • 8
2

Most of the posted solutions using array functions such as filter are incomplete because they aren't parameterized.

Here goes a solution with which the element to count can be set at run time.

function elementsCount(elementToFind, total, number){
    return total += number==elementToFind;
}

var ar = [1, 2, 3, 5, 2, 8, 9, 2];
var elementToFind=2;
var result = ar.reduce(elementsCount.bind(this, elementToFind), 0);

The advantage of this approach is that could easily change the function to count for instance the number of elements greater than X.

You may also declare the reduce function inline

var ar = [1, 2, 3, 5, 2, 8, 9, 2];
var elementToFind=2;
var result = ar.reduce(function (elementToFind, total, number){
    return total += number==elementToFind;
}.bind(this, elementToFind), 0);
Luis Orantes
  • 407
  • 5
  • 13
  • `var elementToFind=2; ... function (elementToFind, total, number){ return total += number==elementToFind; }.bind(this, elementToFind) ...` is harder to read and gives no advantage over just `... (acc, x) => acc += number == 2...`. I like your use of `+=` instead of `acc + (number == 2)` though. Feels like an unwarranted syntax HACK though. – masterxilo Oct 15 '18 at 14:46
2

It is better to wrap it into function:

let countNumber = (array,specificNumber) => {
    return array.filter(n => n == specificNumber).length
}

countNumber([1,2,3,4,5],3) // returns 1
Justin Herrera
  • 526
  • 4
  • 11
2

I use this:

function countElement(array, element) {
  let tot = 0;
  for(var el of array) {
    if(el == element) {
      tot++;
    }
  }
  return tot;
}

var arr = ["a", "b", "a", "c", "d", "a", "e", "f", "a"];

console.log(countElement(arr, "a")); // 4
Deteta
  • 41
  • 4
1

var arrayCount = [1,2,3,2,5,6,2,8];
var co = 0;
function findElement(){
    arrayCount.find(function(value, index) {
      if(value == 2)
        co++;
    });
    console.log( 'found' + ' ' + co + ' element with value 2');
}

I would do something like that:

var arrayCount = [1,2,3,4,5,6,7,8];

function countarr(){
  var dd = 0;
  arrayCount.forEach( function(s){
    dd++;
  });

  console.log(dd);
}
roni
  • 19
  • 5
1

I believe what you are looking for is functional approach

    const arr = ['a', 'a', 'b', 'g', 'a', 'e'];
    const count = arr.filter(elem => elem === 'a').length;
    console.log(count); // Prints 3

elem === 'a' is the condition, replace it with your own.

Shantanu Bhadoria
  • 14,202
  • 1
  • 12
  • 9
  • It won't print 3, but 0. To fix it, your second line should be `count = arr.filter(elem => elem === 'a').length` or `count = arr.filter(elem => {return elem === 'a'}).length` – Wilfredo Pomier Mar 29 '19 at 22:19
1

Array.prototype.count = function (v) {
    var c = 0;
    for (let i = 0; i < this.length; i++) {
        if(this[i] === v){
            c++;
        }
    }
    return c;
}

var arr = [1, 2, 3, 5, 2, 8, 9, 2];

console.log(arr.count(2)); //3
Blackjack
  • 1,322
  • 1
  • 16
  • 21
1

You can use built-in function Array.filter()

array.filter(x => x === element).length;

var arr = [1, 2, 3, 5, 2, 8, 9, 2];

// Count how many 2 there are in arr
var count = arr.filter(x => x === 2).length;

console.log(count);
Blackjack
  • 1,322
  • 1
  • 16
  • 21
0

Solution by recursion

function count(arr, value) {
   if (arr.length === 1)    {
      return arr[0] === value ? 1 : 0;
   } else {
      return (arr.shift() === value ? 1 : 0) + count(arr, value);
   }
}

count([1,2,2,3,4,5,2], 2); // 3
Giffo
  • 4,161
  • 3
  • 15
  • 16
  • 1
    Does this handle an empty array? – Andrew Grimm May 31 '17 at 08:00
  • @AndrewGrimm has it right. Base case is arr.length == 0 – Justin Meiners Oct 04 '18 at 18:15
  • Nice solution! I was trying to do something using recursion just for practice and your example was more elegant than what I was doing. It's definitely a more complex way than using `filter`, `reduce` or a simple `forLoop`, and also, more expensive when looking at performance, but still a great way of doing it with recursion. My only change is: I just think it would be better to create a function and add a filter inside it to copy the array and avoid a mutation of the original array, then use the recursive as an inner function. – R. Marques Oct 28 '19 at 20:28
0

Create a new method for Array class in core level file and use it all over your project.

// say in app.js
Array.prototype.occurrence = function(val) {
  return this.filter(e => e === val).length;
}

Use this anywhere in your project -

[1, 2, 4, 5, 2, 7, 2, 9].occurrence(2);
// above line returns 3
0

Here is a one liner in javascript.

  1. Use map. Find the matching values (v === 2) in the array, returning an array of ones and zeros.
  2. Use Reduce. Add all the values of the array for the total number found.
[1, 2, 3, 5, 2, 8, 9, 2]
  .map(function(v) {
    return v === 2 ? 1 : 0;
  })
  .reduce((a, b) => a + b, 0);

The result is 3.

Lin Du
  • 88,126
  • 95
  • 281
  • 483
Jake
  • 1
0

Depending on how you want to run it:

const reduced = (array, val) => { // self explanatory
    return array.filter((element) => element === val).length;
}

console.log(reduced([1, 2, 3, 5, 2, 8, 9, 2], 2));

// 3

const reducer = (array) => { // array to set > set.forEach > map.set
    const count = new Map();
    const values = new Set(array);
    values.forEach((element)=> {
        count.set(element, array.filter((arrayElement) => arrayElement === element).length);
    });
    return count;
}
console.log(reducer([1, 2, 3, 5, 2, 8, 9, 2]));

// Map(6) {1 => 1, 2 => 3, 3 => 1, 5 => 1, 8 => 1, …}
0

One-liner function

const countBy = (a,f)=>a.reduce((p,v,i,x)=>p+!!f(v,i,x), 0)
countBy([1,2,3,4,5], v=>v%2===0) // 2
nkitku
  • 4,779
  • 1
  • 31
  • 27
0

There are many ways to find out. I think the easiest way is to use the array filter method which is introduced in es6.

function itemCount(array, item) {
    return array.filter(element => element === item).length
}

const myArray = [1,3,5,7,1,2,3,4,5,1,9,0,1]
const items = itemCount(myArray, 1)
console.log(items)
Bar
  • 1,334
  • 1
  • 8
  • 21
0

Something a little more generic and modern (in 2022):

import {pipe, count} from 'iter-ops';

const arr = [1, 2, 3, 5, 2, 8, 9, 2];

const n = pipe(arr, count(a => a === 2)).first; //=> 3

What's good about this:

  1. It counts without creating a new array, so it is memory-efficient
  2. It works the same for any Iterable and AsyncIterable
vitaly-t
  • 24,279
  • 15
  • 116
  • 138
-1

Another approach using RegExp

const list = [1, 2, 3, 5, 2, 8, 9, 2]
const d = 2;
const counter = (`${list.join()},`.match(new RegExp(`${d}\\,`, 'g')) || []).length

console.log(counter)

The Steps follows as below

  1. Join the string using a comma Remember to append ',' after joining so as not to have incorrect values when value to be matched is at the end of the array
  2. Match the number of occurrence of a combination between the digit and comma
  3. Get length of matched items
Owen Kelvin
  • 14,054
  • 10
  • 41
  • 74
-1

I believe you can use the new Set array method of JavaScript to have unique values.

Example:

var arr = [1, 2, 3, 5, 2, 8, 9, 2]
var set = new Set(arr);
 
console.log(set);

// 1,2,3,5,8,9 . We get unique values as output.

vimuth
  • 5,064
  • 33
  • 79
  • 116
-7

You can use length property in JavaScript array:

var myarray = [];
var count = myarray.length;//return 0

myarray = [1,2];
count = myarray.length;//return 2
Stephen Rauch
  • 47,830
  • 31
  • 106
  • 135