Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
329 views
in Technique[技术] by (71.8m points)

javascript - 如何计算数组中某些元素的数量?(How to count the number of certain element in an array?)

If I have an array [1, 2, 3, 5, 2, 8, 9, 2] , I would like to check how many 2 s there are in the array.

(如果我有一个数组[1, 2, 3, 5, 2, 8, 9, 2] ,我想检查数组中有多少2 。)

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

(在JavaScript中不使用for循环进行循环的最优雅的方法是什么?)

  ask by Leem translate from so

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

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

([ 这个答案有点过时:请阅读编辑内容 ])

Say hello to your friends: map and filter and reduce and forEach and every etc.

(问好你的朋友: mapfilter以及reduceforEachevery等)

(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}).length instead)

((我们可以写成.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.

(虽然这个答案可能很可爱,但是js编译器可能不会(或由于规范而无法)优化这种情况。)

So you should really write a simple for loop:

(因此,您应该真正编写一个简单的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.

(您可以定义版本.countStrictEq(...) ,它使用===等式的概念。)

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 .countEq or .countNonstrict stresses it uses the == operator.)

((例如[1,10,3,'10'].count(10)==2 ,因为javascript中像'4'== 4之类的数字...因此将其.countEq.countNonstrict强调它使用==运算符。))

Also consider using your own multiset data structure (eg 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 .

(旁注:但是,如果您仍然希望使用函数式编程的方式(或者在不重写Array.prototype的情况下使用一次性代码),则可以将其编写为[...].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.

(如果您在乎性能,请注意,尽管这与for循环(O(N)时间)渐近相同,但它可能需要O(N)额外的内存(而不是O(1)内存),因为它将几乎当然会生成一个中间数组,然后计算该中间数组的元素。)


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...