如何计算数组中某些元素的数量?
如果我有一个数组[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++; }
[ 这个答案有点过时:阅读编辑 ]
向你的朋友问好: map
和filter
, reduce
和every
等。
(我只是偶尔在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