javascript - 惯用地查找给定值在数组中出现的次数

标签 javascript arrays

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

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

执行此操作最惯用/最优雅的方法是什么?

最佳答案

reduce 在这里比 filter 更合适,因为它不会构建一个临时数组来进行计数。

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

关于javascript - 惯用地查找给定值在数组中出现的次数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17313268/

相关文章:

javascript - 如何将灯箱图像添加到 bxslider(尝试使用 colorbox)

javascript - 按字母数字顺序对一组 li 标签进行排序

javascript - 修复 jQuery 下拉列表中的宽度

javascript - 无法使用 json 对象通过 Javascript 显示动态表

javascript - 获取数据 MySQL DB 并在 HTML 中显示

javascript - 用同位素过滤组合

c++ - 我究竟做错了什么? (C++ 字符串)

java - 使用常量声明数组大小的优点是什么

java - 二维数组尝试正确显示

c++ - 堆栈上的可变大小数组