Подтвердить что ты не робот

Идиоматически найти количество вхождений, которое данное значение имеет в массиве

У меня есть массив с повторяющимися значениями. Я хотел бы найти количество вхождений для любого заданного значения.

Например, если у меня есть массив, определяемый так: var dataset = [2,2,4,2,6,4,7,8];, я хочу найти количество вхождений определенного значения в массиве. То есть программа должна показать, что если у меня есть 3 вхождения значения 2, 1 вхождение значения 6 и т.д.

Какой самый идиоматический/элегантный способ сделать это?

4b9b3361

Ответ 1

reduce данном случае более подходящим является 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);

Ответ 2

Новые браузеры только благодаря использованию 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

Ответ 3

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

Ответ 4

Вот один из способов сразу показать ВСЕ:

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
//}

Ответ 5

Используя обычный цикл, вы можете найти вхождения последовательно и надежно:

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

ДЕМО: https://jsfiddle.net/a7q9k4uu/

Чтобы сделать его более универсальным, функция может принять функцию предиката с пользовательской логикой (возвращающей 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

ДЕМО: https://jsfiddle.net/57en9nar/1/

Ответ 6

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
//  }

Ответ 7

Вы можете использовать метод 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;

Ответ 8

Вы можете подсчитать все элементы в массиве в одной строке, используя сокращение.

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

Это даст объект, ключи которого являются отдельными элементами в массиве, а значения - это количество вхождений элементов в массиве. Затем вы можете получить доступ к одному или нескольким подсчетам, обратившись к соответствующему ключу на объекте.

Например, если вы должны были обернуть это в функции с именем 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

Ответ 9

Я нашел более полезным получить список объектов с ключом для подсчета и ключом для подсчета:

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)

который возвращает:

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

Это не самый чистый метод, и если кто - нибудь знает, как достичь того же результата с reduce, дайте мне знать. Тем не менее, он дает результат, с которым довольно легко работать.

Ответ 10

Во-первых, вы можете использовать решение Brute Force Solution, перейдя к линейному поиску.

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

Однако для этого мы получаем сложность по времени как O (n). Но с помощью бинарного поиска мы можем улучшить нашу сложность.