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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/17313268/
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-10-27 07:51:03  来源:igfitidea点击:

Idiomatically find the number of occurrences a given value has in an array

javascriptarrays

提问by Shrey Gupta

I have an array with repeating values. I would like to find the number of occurrences for any given value.

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

For example, if I have an array defined as so: var dataset = [2,2,4,2,6,4,7,8];, I want to find the number of occurrences of a certain value in the array. That is, the program should show that if I have 3 occurrences of the value 2, 1 occurrence of the value 6, and so on.

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

What's the most idiomatic/elegant way to do this?

什么是最惯用/优雅的方式来做到这一点?

回答by georg

reduceis more appropriate here than filteras it doesn't build a temporary array just for counting.

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

In ES6:

在 ES6 中:

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

Note that it's easy to extend that to use a custom matching predicate, for example, to count objects that have a specific property:

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

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

Counting all items, that is, making an object like {x:count of xs}is complicated in javascript, because object keys can only be strings, so you can't reliably count an array with mixed types. Still, the following simple solution will work well in most cases:

计算所有项目,即{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 update

2017年更新

In ES6, you use the Mapobject to reliably count objects of arbitrary types.

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

A type-aware implementation of Countercan look like this (Typescript):

的类型感知实现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);

回答by Julian Wagner

array.filter(c => c === searchvalue).length;

回答by goat

Newer browsers only due to using Array.filter

较新的浏览器仅因使用 Array.filter

var dataset = [2,2,4,2,6,4,7,8];
var search = 2;
var occurrences = dataset.filter(function(val) {
    return val === search;
}).length;
console.log(occurrences); // 3

回答by Salman A

Here is one way to show ALLcounts at once:

这是一次显示所有计数的一种方法:

var dataset = [2, 2, 4, 2, 6, 4, 7, 8];
var counts = {}, i, value;
for (i = 0; i < dataset.length; i++) {
    value = dataset[i];
    if (typeof counts[value] === "undefined") {
        counts[value] = 1;
    } else {
        counts[value]++;
    }
}
console.log(counts);
// Object {
//    2: 3,
//    4: 2,
//    6: 1,
//    7: 1,
//    8: 1
//}

回答by Ian

Using a normal loop, you can find the occurrences consistently and reliably:

使用普通循环,您可以一致且可靠地找到出现的情况:

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

function getNumMatches(array, valToFind) {
    let numMatches = 0;
    for (let i = 0, j = array.length; i < j; i += 1) {
        if (array[i] === valToFind) {
            numMatches += 1;
        }
    }
    return numMatches;
}

alert(getNumMatches(dataset, 2)); // should alert 3

DEMO:https://jsfiddle.net/a7q9k4uu/

演示:https : //jsfiddle.net/a7q9k4uu/

To make it more generic, the function could accept a predicate function with custom logic (returning true/false) which would determine the final count. For example:

为了使其更通用,该函数可以接受具有自定义逻辑(返回true/ false)的谓词函数,该逻辑将确定最终计数。例如:

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

function getNumMatches(array, predicate) {
    let numMatches = 0;
    for (let i = 0, j = array.length; i < j; i += 1) {
        const current = array[i];
        if (predicate(current) === true) {
            numMatches += 1;
        }
    }
    return numMatches;
}

const numFound = getNumMatches(dataset, (item) => {
    return item === 2;
});

alert(numFound); // should alert 3

DEMO:https://jsfiddle.net/57en9nar/1/

演示:https : //jsfiddle.net/57en9nar/1/

回答by Manolis

var dataset = [2,2,4,2,6,4,7,8], count = {}

dataset.forEach(function(el){
    count[el] = count[el] + 1 || 1
});

console.log(count)

//  {
//    2: 3,
//    4: 2,
//    6: 1,
//    7: 1,
//    8: 1
//  }

回答by rab

You can do with use of array.reduce(callback[, initialValue])method in JavaScript 1.8

你可以使用array.reduce(callback[, initialValue])方法来做JavaScript 1.8

var dataset = [2,2,4,2,6,4,7,8],
    dataWithCount = dataset.reduce( function( o , v ) {

        if ( ! o[ v ] ) {
            o[ v ] = 1 ;  
        }  else {
            o[ v ] = o[ v ] + 1;
        }      

        return o ;    

    }, {} );

// print data with count.
for( var i in  dataWithCount ){
     console.log( i + 'occured ' + dataWithCount[i] + 'times ' ); 
}

// find one number
var search = 2,
    count = dataWithCount[ search ] || 0;

回答by justin.m.chase

You can count all items in an array, in a single line, using reduce.

您可以使用reduce 在一行中计算数组中的所有项目。

[].reduce((a,b) => (a[b] = a[b] + 1 || 1) && a, {})

This will yield an object, whose keys are the distinct elements in the array and values are the count of occurences of elements in the array. You can then access one or more of the counts by accessing a corresponding key on the object.

这将产生一个对象,其键是数组中的不同元素,值是数组中元素出现的次数。然后,您可以通过访问对象上的相应键来访问一个或多个计数。

For example if you were to wrap the above in a function called count():

例如,如果您要将上述内容包装在一个名为 的函数中count()

function count(arr) {
  return arr.reduce((a,b) => (a[b] = a[b] + 1 || 1) && a, {})
}

count(['example'])          // { example: 1 }
count([2,2,4,2,6,4,7,8])[2] // 3

回答by crash springfield

I've found it more useful to end up with a list of objects with a key for what is being counted and a key for the count:

我发现最终得到一个对象列表更有用,其中包含一个用于计数的键和一个用于计数的键:

const data = [2,2,4,2,6,4,7,8]
let counted = []
for (var c of data) {
  const alreadyCounted = counted.map(c => c.name)
  if (alreadyCounted.includes(c)) {
    counted[alreadyCounted.indexOf(c)].count += 1
  } else {
    counted.push({ 'name': c, 'count': 1})
  }
}
console.log(counted)

which returns:

返回:

[ { name: 2, count: 3 },
  { name: 4, count: 2 },
  { name: 6, count: 1 },
  { name: 7, count: 1 },
  { name: 8, count: 1 } ]

It isn't the cleanest method, and if anyone knows how to achieve the same result with reducelet me know. However, it does produce a result that's fairly easy to work with.

这不是最干净的方法,如果有人知道如何实现相同的结果,请reduce告诉我。然而,它确实产生了一个相当容易使用的结果。

回答by crash springfield

First, you can go with Brute Force Solution by going with Linear Search.

首先,您可以通过线性搜索来使用蛮力解决方案。

public int LinearSearchcount(int[] A, int data){
  int count=0;
  for(int i=0;i<A.length;i++) {
    if(A[i]==data) count++;
  }
  return count;
}

However, for going with this, we get Time complexity as O(n).But by going with Binary search, we can improve our Complexity.

然而,为此,我们得到时间复杂度为 O(n)。但是通过二分搜索,我们可以提高我们的复杂度。