我有一个数组:

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

我想知道数组中有多少个2。

在JavaScript中,没有for循环的最优雅的方法是什么?


当前回答

在核心级别文件中为Array类创建一个新方法,并在整个项目中使用它。

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

在项目的任何地方使用这个-

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

其他回答

我用这个:

函数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

为什么需要map或filter呢? Reduce是为这类操作而“诞生”的:

[1、2、3、5、2、8、9、2]。减少((count,2)=>count+(item==val), 0);

就是这样!(如果item==val在每次迭代中,那么1将被添加到累加器计数中,因为true将解析为1)。

作为函数:

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

或者,继续扩展你的数组:

Array.prototype.count = function(val) {
   return this.reduce((count,item)=>count+(item==val),0)
}

非常简单:

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

[这个答案有点过时了:阅读编辑,在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.

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