如何计算数组中某些元素的数量?

如果我有一个数组[1, 2, 3, 5, 2, 8, 9, 2] ,我想检查数组中有多less个2 。 什么是最优雅的方式来做,而不循环for循环的JavaScript?

很简单:

 var count = 0; for(var i = 0; i < array.length; ++i){ if(array[i] == 2) count++; } 

[ 这个答案有点过时:阅读编辑 ]

向你的朋友问好: mapfilterreduceevery等。

(我只是偶尔在javascript中编写for-loops,因为块级别的范围是缺less的,所以如果你需要捕获或克隆你的迭代索引或值,你必须使用函数作为循环的主体。一般来说效率更高,但有时需要closures。)

最可读的方式:

 [...].filter(function(x){return x==2}).length 

下面是更节省空间(O(1),而不是O(N)),但我不知道你可能会花费多less时间(不超过一个恒定的因素,因为你访问每个元素恰好一次):

 [...].reduce(function(total,x){return x==2 ? total+1 : total}, 0) 

(如果你需要优化这段特定的代码,在某些浏览器上for循环可能会更快…你可以在jsperf.com上testing一下。)


然后,你可以优雅,把它变成一个原型function:

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

喜欢这个:

 Object.defineProperties(Array.prototype, { count: { value: function(value) { return this.reduce(...); } } }); 

你也可以在上面的属性定义里面粘上常规的旧的for-loop技术(参见其他答案)(可能会更快)。


2017编辑

哎呀,这个答案比正确的答案更受欢迎。 其实只要用接受的答案 虽然这个答案可能很可爱,但js编译器可能不会(或不能由于spec)优化这种情况。 所以你应该写一个简单的for循环:

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

你可以定义一个版本.countStrictEq(...) ,它使用===等式的概念。 平等的概念可能对你正在做的事很重要! (例如[1,10,3,'10'].count(10)==2 ,因为数字像'4'== 4 …因此调用它.countEq.countNonstrict强调它使用==运算符。)

还可以考虑使用自己的multiset数据结构(例如像python的“ collections.Counter ”),以避免首先进行计数。

 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 {} } } 

演示:

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

虽然,如果你仍然需要函数式编程的方式,那么现在可以把它写得更简洁一些: [...].filter(x => x==2).length

2017:如果有人仍然对这个问题感兴趣,我的解决scheme如下:

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

如果使用lodash或下划线,则_.countBy方法将提供数组中每个值键入的聚合总计对象。 如果你只需要计算一个值,你可以把它变成一行:

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

这也适用于数组数组。 你的例子中的单行将是:

 _.countBy([1, 2, 3, 5, 2, 8, 9, 2])[2]; // 3 

大多数使用诸如filter之类的数组函数的解决scheme都是不完整的,因为它们没有被参数化。

这里有一个解决scheme,可以在运行时设置要计数的元素。

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

这种方法的优点是可以很容易地改变函数来计算大于X的元素的数量。

你也可以声明reduce函数内联

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

不使用循环通常意味着把过程交给一些使用循环的方法。

这是一个我们的循环讨厌编码器可以满足他的厌恶,在一个价格的方式:

 var a=[1, 2, 3, 5, 2, 8, 9, 2]; alert(String(a).replace(/[^2]+/g,'').length); /* returned value: (Number) 3 */ 

你也可以重复调用indexOf,如果它是可用的数组方法,并且每次移动search指针。

这不会创build一个新的数组,循环比forEach或filter更快。

如果你有一百万名会员来看,这可能会有所帮助。

 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 */ 

通过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 
 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'); } 

ES6更新到JS:

 // Let has local scope let array = [1, 2, 3, 5, 2, 8, 9, 2] // Functional filter with an Arrow function array.filter(x => x===2).length 

JS中的一致的箭头函数(lambda函数)

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

可以简化为单一input的简洁格式:

 x => 2 * x 

隐含回报的地方。

我能想到的最奇怪的方式是:

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

哪里:

  • 一个是数组
  • n是数组中要计数的数字

我的build议,使用一段时间或for循环;-)

您可以在JavaScript数组中使用length属性:

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