Подсчет вхождений / частоты элементов массива - PullRequest
184 голосов
/ 14 апреля 2011

В Javascript я пытаюсь взять начальный массив числовых значений и сосчитать элементы внутри него.В идеале, результатом должны быть два новых массива, первый из которых определяет каждый уникальный элемент, а второй содержит количество раз, которое встречается каждый элемент.Однако я открыт для предложений по формату вывода.

Например, если начальный массив был:

5, 5, 5, 2, 2, 2, 2, 2, 9, 4

Тогда будут созданы два новых массива.Первый будет содержать имя каждого уникального элемента:

5, 2, 9, 4

Второй будет содержать число раз, которое элемент встречался в исходном массиве:

3, 5, 1, 1

Поскольку число 5 происходиттри раза в исходном массиве число 2 встречается пять раз, а 9 и 4 появляются один раз.

Я много искал решение, но, похоже, ничего не работает, и все, что я пробовал самв итоге оказался нелепо сложным.Любая помощь будет оценена!

Спасибо:)

Ответы [ 35 ]

8 голосов
/ 16 октября 2013

Если вы используете подчеркивание, вы можете перейти по функциональному маршруту

a = ['foo', 'foo', 'bar'];

var results = _.reduce(a,function(counts,key){ counts[key]++; return counts },
                  _.object( _.map( _.uniq(a), function(key) { return [key, 0] })))

, чтобы ваш первый массив был

_.keys(results)

, а второй -

_.values(results)

большинство из них по умолчанию будут использовать нативные функции javascript, если они доступны

demo: http://jsfiddle.net/dAaUU/

6 голосов
/ 01 октября 2016

На основе ответа из @ adamse и @ pmandell (что я поддерживаю), в ES6 вы можете сделать это в одна строка :

  • 2017 edit : я использую ||, чтобы уменьшить размер кода и сделать его более читабельным.

var a=[7,1,7,2,2,7,3,3,3,7,,7,7,7];
alert(JSON.stringify(

a.reduce((r,k)=>{r[k]=1+r[k]||1;return r},{})

));

Может использоваться для подсчета символов :

var s="ABRACADABRA";
alert(JSON.stringify(

s.split('').reduce((a, c)=>{a[c]++?0:a[c]=1;return a},{})

));
5 голосов
/ 05 февраля 2019

Итак, вот как я могу сделать это с некоторыми из новейших функций JavaScript:

Во-первых, уменьшите массив до Map из числа:

let countMap = array.reduce(
  (map, value) => {map.set(value, (map.get(value) || 0) + 1); return map}, 
  new Map()
)

Используя Map, ваш начальный массив может содержать объекты любого типа, и количество будет правильным.Без Map некоторые типы объектов будут давать странные подсчеты.См. Map документы для получения дополнительной информации о различиях.

Это также может быть сделано с объектом, если все ваши значения являются символами, числами или строками:

let countObject = array.reduce(
  (map, value) => { map[value] = (map[value] || 0) + 1; return map },
  {}
)

Или немного более функционально, без мутаций, используя деструктуризацию и синтаксис распространения объекта:

let countObject = array.reduce(
  (value, {[value]: count = 0, ...rest}) => ({ [value]: count + 1, ...rest }),
  {}
)

На данный момент вы можете использовать Map или объект для подсчета (и картуявляется прямым итератором, в отличие от объекта), или преобразует его в два массива.

Для Map:

countMap.forEach((count, value) => console.log(`value: ${value}, count: ${count}`)

let values = countMap.keys()
let counts = countMap.values()

Или для объекта:

Object
  .entries(countObject) // convert to array of [key, valueAtKey] pairs
  .forEach(([value, count]) => console.log(`value: ${value}, count: ${count}`)

let values = Object.keys(countObject)
let counts = Object.values(countObject)
5 голосов
/ 15 апреля 2011

Вы можете расширить прототип Array следующим образом:

Array.prototype.frequencies = function() {
    var l = this.length, result = {all:[]};
    while (l--){
       result[this[l]] = result[this[l]] ? ++result[this[l]] : 1;
    }
    // all pairs (label, frequencies) to an array of arrays(2)
    for (var l in result){
       if (result.hasOwnProperty(l) && l !== 'all'){
          result.all.push([ l,result[l] ]);
       }
    }
    return result;
};

var freqs = [5, 5, 5, 2, 2, 2, 2, 2, 9, 4].frequencies();
alert(freqs[2]); //=> 5
// or
var freqs = '1,1,2,one,one,2,2,22,three,four,five,three,three,five'
             .split(',')
             .frequencies();
alert(freqs.three); //=> 3

В качестве альтернативы вы можете использовать Array.map:

  Array.prototype.frequencies  = function () {
    var freqs = {sum: 0}; 
    this.map( function (a){ 
        if (!(a in this)) { this[a] = 1; } 
        else { this[a] += 1; }
        this.sum += 1;
        return a; }, freqs
    );
    return freqs;
  }
5 голосов
/ 25 апреля 2013

Вот что-то легкое и легкое для глаз ...

function count(a,i){
 var result = 0;
 for(var o in a)
  if(a[o] == i)
   result++;
 return result;
}

Редактировать: А так как вы хотите, чтобы все происходило ...

function count(a){
 var result = {};
 for(var i in a){
  if(result[a[i]] == undefined) result[a[i]] = 0;
  result[a[i]]++;
 }
 return result;
}
4 голосов
/ 21 апреля 2017
var array = [5, 5, 5, 2, 2, 2, 2, 2, 9, 4];

function countDuplicates(obj, num){
  obj[num] = (++obj[num] || 1);
  return obj;
}

var answer = array.reduce(countDuplicates, {});
// answer => {2:5, 4:1, 5:3, 9:1};

Если вы все еще хотите два массива, то вы можете использовать answer вот так ...

var uniqueNums = Object.keys(answer);
// uniqueNums => ["2", "4", "5", "9"];

var countOfNums = Object.keys(answer).map(key => answer[key]);
// countOfNums => [5, 1, 3, 1];

Или, если вы хотите, чтобы uniqueNums были числами

var uniqueNums = Object.keys(answer).map(key => +key);
// uniqueNums => [2, 4, 5, 9];
3 голосов
/ 18 февраля 2018

ES6 решение с уменьшением (фиксированное):

const arr = [2, 2, 2, 3, 2]

const count = arr.reduce((pre, cur) => (cur === 2) ? ++pre : pre, 0)
console.log(count) // 4
2 голосов
/ 12 февраля 2019

Мое решение с рамдой:

const testArray = [5, 5, 5, 2, 2, 2, 2, 2, 9, 4]

const counfFrequency = R.compose(
  R.map(R.length),
  R.groupBy(R.identity),
)

counfFrequency(testArray)

Ссылка на REPL.

1 голос
/ 02 августа 2012

Попробуйте это:

Array.prototype.getItemCount = function(item) {
    var counts = {};
    for(var i = 0; i< this.length; i++) {
        var num = this[i];
        counts[num] = counts[num] ? counts[num]+1 : 1;
    }
    return counts[item] || 0;
}
1 голос
/ 14 апреля 2011

Проверьте код ниже.

<html>
<head>
<script>
// array with values
var ar = [5, 5, 5, 2, 2, 2, 2, 2, 9, 4];

var Unique = []; // we'll store a list of unique values in here
var Counts = []; // we'll store the number of occurances in here

for(var i in ar)
{
    var Index = ar[i];
    Unique[Index] = ar[i];
    if(typeof(Counts[Index])=='undefined')  
        Counts[Index]=1;
    else
        Counts[Index]++;
}

// remove empty items
Unique = Unique.filter(function(){ return true});
Counts = Counts.filter(function(){ return true});

alert(ar.join(','));
alert(Unique.join(','));
alert(Counts.join(','));

var a=[];

for(var i=0; i<Unique.length; i++)
{
    a.push(Unique[i] + ':' + Counts[i] + 'x');
}
alert(a.join(', '));

</script>
</head>
<body>

</body>
</html>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...