我有一个数组:

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

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

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


当前回答

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

其他回答

一些更普通和现代的东西(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

这样做的好处是:

它不需要创建一个新的数组,所以它是内存高效的 对于任何Iterable和AsyncIterable都是一样的

这是javascript中的一行代码。

使用地图。在数组中找到匹配的值(v === 2),返回一个由1和0组成的数组。 使用减少。将该数组的所有值相加,得到所找到的总数。

[1, 2, 3, 5, 2, 8, 9, 2]
  .map(function(v) {
    return v === 2 ? 1 : 0;
  })
  .reduce((a, b) => a + b, 0);

结果是3。

Array.prototype.count =函数(v) { Var c = 0; 对于(设I = 0;I < this.length;我+ +){ If (this[i] === v){ c++; } } 返回c; } Var arr = [1,2,3,5,2,8,9,2]; console.log (arr.count (2));/ / 3

你可以使用内置函数Array.filter()

数组中。Filter (x => x === element).length;

Var arr = [1,2,3,5,2,8,9,2]; //数一下arr中有多少个2 Var计数= arr。Filter (x => x == 2).length; console.log(数);

非常简单:

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