一尘不染

惯用地找到给定值在数组中出现的次数

javascript

我有一个重复值的数组。我想找到任何给定值的出现次数。

例如,如果我有一个这样定义的数组:var dataset = [2,2,4,2,6,4,7,8];,我想查找数组中某个值出现的次数。也就是说,程序应该显示如果我出现3次value 2,发生1次value
6,依此类推。

什么是最惯用/优雅的方法?


阅读 279

收藏
2020-05-01

共1个答案

一尘不染

reducefilter它不仅仅建立用于计数的临时数组,在这里更合适。

var dataset = [2,2,4,2,6,4,7,8];

var search = 2;



var count = dataset.reduce(function(n, val) {

    return n + (val === search);

}, 0);



console.log(count);

在ES6中:

let count = dataset.reduce((n, x) => n + (x === search), 0);

请注意,使用自定义匹配谓词进行扩展很容易,例如,对具有特定属性的对象进行计数:

people = [

    {name: 'Mary', gender: 'girl'},

    {name: 'Paul', gender: 'boy'},

    {name: 'John', gender: 'boy'},

    {name: 'Lisa', gender: 'girl'},

    {name: 'Bill', gender: 'boy'},

    {name: 'Maklatura', gender: 'girl'}

]



var numBoys = people.reduce(function (n, person) {

    return n + (person.gender == 'boy');

}, 0);



console.log(numBoys);

{x:count of xs}在javascript中,对所有项目进行计数(即使对象类似)很复杂,因为对象键只能是字符串,因此无法可靠地对具有混合类型的数组进行计数。不过,以下简单的解决方案在大多数情况下仍然可以正常使用:

count = function (ary, classifier) {

    classifier = classifier || String;

    return ary.reduce(function (counter, item) {

        var p = classifier(item);

        counter[p] = counter.hasOwnProperty(p) ? counter[p] + 1 : 1;

        return counter;

    }, {})

};



people = [

    {name: 'Mary', gender: 'girl'},

    {name: 'Paul', gender: 'boy'},

    {name: 'John', gender: 'boy'},

    {name: 'Lisa', gender: 'girl'},

    {name: 'Bill', gender: 'boy'},

    {name: 'Maklatura', gender: 'girl'}

];



// If you don't provide a `classifier` this simply counts different elements:



cc = count([1, 2, 2, 2, 3, 1]);

console.log(cc);



// With a `classifier` you can group elements by specific property:



countByGender = count(people, function (item) {

    return item.gender

});

console.log(countByGender);

2017更新

在ES6中,您可以使用Map对象可靠地计算任意类型的对象。

class Counter extends Map {

    constructor(iter, key=null) {

        super();

        this.key = key || (x => x);

        for (let x of iter) {

            this.add(x);

        }

    }

    add(x) {

      x = this.key(x);

      this.set(x, (this.get(x) || 0) + 1);

    }

}



// again, with no classifier just count distinct elements



results = new Counter([1, 2, 3, 1, 2, 3, 1, 2, 2]);

for (let [number, times] of results.entries())

    console.log('%s occurs %s times', number, times);





// counting objects



people = [

    {name: 'Mary', gender: 'girl'},

    {name: 'John', gender: 'boy'},

    {name: 'Lisa', gender: 'girl'},

    {name: 'Bill', gender: 'boy'},

    {name: 'Maklatura', gender: 'girl'}

];





chessChampions = {

    2010: people[0],

    2012: people[0],

    2013: people[2],

    2014: people[0],

    2015: people[2],

};



results = new Counter(Object.values(chessChampions));

for (let [person, times] of results.entries())

    console.log('%s won %s times', person.name, times);



// you can also provide a classifier as in the above



byGender = new Counter(people, x => x.gender);

for (let g of ['boy', 'girl'])

   console.log("there are %s %ss", byGender.get(g), g);

的类型感知实现Counter可以如下所示(Typescript):

type CounterKey = string | boolean | number;

interface CounterKeyFunc<T> {
    (item: T): CounterKey;
}

class Counter<T> extends Map<CounterKey, number> {
    key: CounterKeyFunc<T>;

    constructor(items: Iterable<T>, key: CounterKeyFunc<T>) {
        super();
        this.key = key;
        for (let it of items) {
            this.add(it);
        }
    }

    add(it: T) {
        let k = this.key(it);
        this.set(k, (this.get(k) || 0) + 1);
    }
}

// example:

interface Person {
    name: string;
    gender: string;
}


let people: Person[] = [
    {name: 'Mary', gender: 'girl'},
    {name: 'John', gender: 'boy'},
    {name: 'Lisa', gender: 'girl'},
    {name: 'Bill', gender: 'boy'},
    {name: 'Maklatura', gender: 'girl'}
];


let byGender = new Counter(people, (p: Person) => p.gender);

for (let g of ['boy', 'girl'])
    console.log("there are %s %ss", byGender.get(g), g);
2020-05-01