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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/6120931/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 20:19:41  来源:igfitidea点击:

How to count certain elements in array?

javascript

提问by Leem

I have an array:

我有一个数组:

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

I would like to know how many 2s are in the array.

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

What is the most elegant way to do it in JavaScript without looping with forloop?

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

采纳答案by Thor Jacobsen

Very simple:

很简单:

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

回答by ninjagecko

[this answer is a bit dated: read the edits]

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

Say hello to your friends: mapand filterand reduceand forEachand everyetc.

向你的朋友问好:mapand filterand reduceand forEachand everyetc.

(I only occasionally write for-loops in javascript, because of block-level scoping is missing, so you have to use a function as the body of the loop anyway if you need to capture or clone your iteration index or value. For-loops are more efficient generally, but sometimes you need a closure.)

(我只是偶尔在 javascript 中编写 for 循环,因为缺少块级范围,所以如果你需要捕获或克隆你的迭代索引或值,无论如何你必须使用一个函数作为循环体。For-loops通常更有效,但有时你需要一个闭包。)

The most readable way:

最易读的方式:

[....].filter(x => x==2).length

(We could have written .filter(function(x){return x==2}).lengthinstead)

(我们本来可以写的.filter(function(x){return x==2}).length

The following is more space-efficient (O(1) rather than O(N)), but I'm not sure how much of a benefit/penalty you might pay in terms of time (not more than a constant factor since you visit each element exactly once):

以下内容更节省空间(O(1) 而不是 O(N)),但我不确定您可能会在时间方面支付多少收益/惩罚(自您访问以来不超过一个常数因素)每个元素恰好一次):

[....].reduce((total,x) => (x==2 ? total+1 : total), 0)

(If you need to optimize this particular piece of code, a for loop might be faster on some browsers... you can test things on jsperf.com.)

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



You can then be elegant and turn it into a prototype function:

然后你可以优雅的把它变成一个原型函数:

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

Like this:

像这样:

Object.defineProperties(Array.prototype, {
    count: {
        value: function(value) {
            return this.filter(x => x==value).length;
        }
    }
});

You can also stick the regular old for-loop technique (see other answers) inside the above property definition (again, that would likely be much faster).

您还可以在上述属性定义中使用常规的旧 for 循环技术(请参阅其他答案)(同样,这可能会快得多)。



2017 edit:

2017年编辑

Whoops, this answer has gotten more popular than the correct answer. Actually, just use the accepted answer. While this answer may be cute, the js compilers probably don't (or can't due to spec) optimize such cases. So you should really write a simple for loop:

哎呀,这个答案比正确答案更受欢迎。实际上,只需使用已接受的答案即可。虽然这个答案可能很可爱,但 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;
        }
    }
});

You could define a version .countStrictEq(...)which used the ===notion of equality. The notion of equality may be important to what you're doing! (for example [1,10,3,'10'].count(10)==2, because numbers like '4'==4 in javascript... hence calling it .countEqor .countNonstrictstresses it uses the ==operator.)

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

Also consider using your own multiset data structure (e.g. like python's 'collections.Counter') to avoid having to do the counting in the first place.

还可以考虑使用您自己的多集数据结构(例如,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 {}
    }
}

Demo:

演示:

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

旁注:不过,如果你仍然想要函数式编程方式(或者不覆盖 Array.prototype 的一次性单行代码),你现在可以更简洁地将它写成[...].filter(x => x==2).length. 如果您关心性能,请注意,虽然这与 for 循环(O(N) 时间)的性能渐近相同,但它可能需要 O(N) 额外内存(而不是 O(1) 内存),因为它几乎当然生成一个中间数组,然后计算该中间数组的元素。

回答by Raild

2017:If someone is still interested in the question, my solution is the following:

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

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

回答by Sverrisson

ES6 Update to JS:

ES6 对 JS 的更新:

Note that you should always use triple equals: ===to get correct comparison:

请注意,您应该始终使用三重等号:===来获得正确的比较:

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

The following unanimous Arrow function(lambda function) in JS:

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

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

may be simplified to this concise form for a single input:

对于单个输入,可以简化为这种简洁的形式:

x => 2 * x

where the returnis implied.

其中return的暗示。

回答by Coleman

If you are using lodash or underscore the _.countBymethod will provide an object of aggregate totals keyed by each value in the array. You can turn this into a one-liner if you only need to count one value:

如果您使用 lodash 或下划线,_.countBy方法将提供一个由数组中的每个值键控的聚合总数对象。如果您只需要计算一个值,您可以将其转换为单行:

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

This also works fine on arrays of numbers. The one-liner for your example would be:

这也适用于数字数组。您的示例的单行是:

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

回答by Gary Green

Weirdest way I can think of doing this is:

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

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

Where:

在哪里:

  • ais the array
  • nis the number to count in the array
  • a是数组
  • n是要在数组中计数的数字

My suggestion, use a while or for loop ;-)

我的建议,使用 while 或 for 循环 ;-)

回答by kennebec

Not using a loop usually means handing the process over to some method that doesuse a loop.

不使用循环通常意味着移交过程切换到一些方法使用循环。

Here is a way our loop hating coder can satisfy his loathing, at a price:

这是我们讨厌循环的编码器可以满足他的厌恶的一种方式,但要付出代价:

var a=[1, 2, 3, 5, 2, 8, 9, 2];

alert(String(a).replace(/[^2]+/g,'').length);


/*  returned value: (Number)
3
*/

You can also repeatedly call indexOf, if it is available as an array method, and move the search pointer each time.

您还可以重复调用 indexOf(如果它可用作数组方法),并每次移动搜索指针。

This does not create a new array, and the loop is faster than a forEach or filter.

这不会创建新数组,并且循环比 forEach 或过滤器快。

It could make a difference if you have a million members to look at.

如果您有 100 万会员可以查看,这可能会有所作为。

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

回答by Luis Orantes

Most of the posted solutions using array functions such as filter are incomplete because they aren't parameterized.

大多数使用数组函数(例如 filter)发布的解决方案都不完整,因为它们没有参数化。

Here goes a solution with which the element to count can be set at run time.

这是一个解决方案,可以在运行时设置要计数的元素。

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

The advantage of this approach is that could easily change the function to count for instance the number of elements greater than X.

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

You may also declare the reduce function inline

您还可以内联声明 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);

回答by Yuval A.

Really, why would you need mapor filterfor this? reducewas "born" for these kind of operations:

真的,你为什么需要mapfilter为此? reduce为这些类型的操作“诞生”:

[1, 2, 3, 5, 2, 8, 9, 2].reduce( (count,2)=>count+(item==val), 0);

[1, 2, 3, 5, 2, 8, 9, 2].reduce( (count,2)=>count+(item==val), 0);

that's it! (if item==valin each iteration, then 1 will be added to the accumulator count, as truewill resolve to 1).

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

As a function:

作为一个函数:

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

Or, go ahead and extend your arrays:

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

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

回答by Justin Herrera

It is better to wrap it into function:

最好将其包装成函数:

let countNumber = (array,specificNumber) => {
    return array.filter(n => n == specificNumber).length
}

countNumber([1,2,3,4,5],3) // returns 1