我有一个数组:
[1, 2, 3, 5, 2, 8, 9, 2]
我想知道数组中有多少个2。
在JavaScript中,没有for循环的最优雅的方法是什么?
我有一个数组:
[1, 2, 3, 5, 2, 8, 9, 2]
我想知道数组中有多少个2。
在JavaScript中,没有for循环的最优雅的方法是什么?
当前回答
2017: 如果有人仍然对这个问题感兴趣,我的解决方法如下:
const arrayToCount = [1,2,3,5,2,8,9,2]; const result = arrayToCount。Filter (i => i == 2).length; Console.log('找到的元素数量:' +结果);
其他回答
不使用循环通常意味着将进程交给一些使用循环的方法。
这里有一个讨厌循环的编码器可以以一定的代价来满足他的厌恶:
var a=[1, 2, 3, 5, 2, 8, 9, 2];
alert(String(a).replace(/[^2]+/g,'').length);
/* returned value: (Number)
3
*/
如果indexOf作为数组方法可用,还可以重复调用indexOf,并每次移动搜索指针。
这不会创建一个新的数组,并且循环比forEach或过滤器更快。
如果你有一百万个会员可以查看,那就会有所不同。
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
*/
这取决于你想如何运行它:
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, …}
我用这个:
函数countElement(数组,元素){ 令tot = 0; For (var el of array) { If (el == element) { 合计+ +; } } 返回合计; } var arr =(“a”、“b”、“a”,“c”,“d”,“一个”,“e”,“f”,“a”); “a”console.log (countElement (arr));/ / 4
我是js数组的reduce函数的开始粉丝。
const myArray =[1, 2, 3, 5, 2, 8, 9, 2];
const count = myArray.reduce((count, num) => num === 2 ? count + 1 : count, 0)
事实上,如果你真的想要花哨一点,你可以在Array原型上创建一个count函数。然后你就可以重复使用了。
Array.prototype.count = function(filterMethod) {
return this.reduce((count, item) => filterMethod(item)? count + 1 : count, 0);
}
然后做
const myArray =[1, 2, 3, 5, 2, 8, 9, 2]
const count = myArray.count(x => x==2)
[这个答案有点过时了:阅读编辑,在javascript中'equal'的概念是模糊的]
向你的朋友问好:映射,过滤,减少,forEach和every等等。
(我只是偶尔用javascript写for-loops,因为缺少块级别的作用域,所以如果你需要捕获或克隆你的迭代索引或值,你必须使用函数作为循环的主体。for循环通常更有效,但有时你需要一个闭包。)
最易读的方式:
[....].filter(x => x==2).length
(我们可以写。filter(function(x){return x==2})。长度)
以下是更节省空间(O(1)而不是O(N)),但我不确定你可能会在时间方面付出多少好处/惩罚(不超过一个常数因子,因为你访问每个元素正好一次):
[....].reduce((total,x) => (x==2 ? total+1 : total), 0)
或者正如一位评论者好心指出的那样:
[....].reduce((total,x) => total+(x==2), 0)
(如果你需要优化这段特定的代码,在某些浏览器上for循环可能更快……你可以在jsperf.com上测试。)
然后你可以优雅地把它变成一个原型函数:
[1, 2, 3, 5, 2, 8, 9, 2].count(2)
是这样的:
Object.defineProperties(Array.prototype, {
count: {
value: function(value) {
return this.filter(x => x==value).length;
}
}
});
您还可以在上面的属性定义中插入常规的for循环技术(参见其他答案)(同样,这可能会快得多)。
2017编辑:
哎呀,这个答案比正确答案更受欢迎。实际上,用公认的答案就行了。虽然这个答案可能很可爱,但js编译器可能不会(或由于规范)优化这种情况。所以你应该写一个简单的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这样的数字在javascript中…因此称它为. counteq或. countnonstrict强调它使用==操作符。)
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().
还可以考虑使用自己的多集数据结构(例如python的'collections.Counter'),以避免首先进行计数。这适用于形式[]的精确匹配。过滤器(x = x = = > ? ?)。长度(最坏情况下O(N)到O(1)),并修改将加快查询形式[].filter(filterFunction)。长度(大约是#total/#duplicate的一个因子)。
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)
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.