我有一个重复值的数组。我想找到任何给定值的出现次数。
例如,如果我有一个这样定义的数组:var dataset = [2,2,4,2,6,4,7,8];,我想查找数组中某个值出现的次数。也就是说,程序应该显示如果我出现3次value 2,发生1次value 6,依此类推。
var dataset = [2,2,4,2,6,4,7,8];
2
6
什么是最惯用/优雅的方法?
reduce比filter它不仅仅建立用于计数的临时数组,在这里更合适。
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中,对所有项目进行计数(即使对象类似)很复杂,因为对象键只能是字符串,因此无法可靠地对具有混合类型的数组进行计数。不过,以下简单的解决方案在大多数情况下仍然可以正常使用:
{x:count of xs}
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);
在ES6中,您可以使用Map对象可靠地计算任意类型的对象。
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):
Counter
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);