Подсчет вхождений / частоты элементов массива

218

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

Например, если исходный массив был:

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

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

5, 2, 9, 4

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

3, 5, 1, 1

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

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

Спасибо :)

Джек W
источник
8
Если все, что вам нужно, это посмотреть, появляется ли значение только один раз (вместо двух или более раз), вы можете использоватьif (arr.indexOf(value) == arr.lastIndexOf(value))
Rodrigo
1
Мы можем использовать ramda.jsдля достижения этого простым способом. const ary = [5, 5, 5, 2, 2, 2, 2, 2, 9, 4]; R.countBy(r=> r)(ary)
Эшвар Прасад Ядданапуди
arr.filter(x => x===5).lengthвозвратился бы, 3чтобы указать, что есть '3' пятерки в массиве.
Нообниня

Ответы:

94

Ну вот:

function foo(arr) {
    var a = [], b = [], prev;

    arr.sort();
    for ( var i = 0; i < arr.length; i++ ) {
        if ( arr[i] !== prev ) {
            a.push(arr[i]);
            b.push(1);
        } else {
            b[b.length-1]++;
        }
        prev = arr[i];
    }

    return [a, b];
}

Демоверсия в реальном времени: http://jsfiddle.net/simevidas/bnACW/

Заметка

Это меняет порядок исходного входного массива, используя Array.sort

Шиме Видас
источник
24
имеет побочный эффект сортировки массива (побочные эффекты плохие), также сортировка есть, O(N log(N))и выигрыш в элегантности не стоит
ninjagecko
1
@ninja Какой другой ответ вы предпочитаете?
Шиме Видас
В отсутствие хорошего высокоуровневого примитива из сторонней библиотеки, я обычно реализую это как reduceответ. Я собирался представить такой ответ, прежде чем увидел, что он уже существует. Тем не менее, counts[num] = counts[num] ? counts[num]+1 : 1ответ также работает (эквивалентно if(!result[a[i]])result[a[i]]=0ответу, который более элегантен, но менее удобен для чтения); эти ответы можно изменить, чтобы использовать «более приятную» версию цикла for, возможно, сторонний цикл for, но я как бы проигнорировал это, поскольку стандартные циклы for на основе индекса, к сожалению, используются по умолчанию.
ninjagecko
2
@ninja Я согласен. Эти ответы лучше. К сожалению, я не могу принять свой собственный ответ.
Шиме Видас
Для сортировки небольших массивов это может быть быстрее, чем создание ассоциативного массива.
Quant_dev
219

Вы можете использовать объект для хранения результатов:

var arr = [5, 5, 5, 2, 2, 2, 2, 2, 9, 4];
var counts = {};

for (var i = 0; i < arr.length; i++) {
  var num = arr[i];
  counts[num] = counts[num] ? counts[num] + 1 : 1;
}

console.log(counts[5], counts[2], counts[9], counts[4]);

Итак, теперь ваш объект count может сказать вам, что это за счет для определенного числа:

console.log(counts[5]); // logs '3'

Если вы хотите получить массив членов, просто используйте keys()функции

keys(counts); // returns ["5", "2", "9", "4"]
тип
источник
3
Следует отметить, что эта Object.keys()функция поддерживается только в IE9 +, FF4 +, SF5 +, CH6 +, но Opera не поддерживает ее. Я думаю, что самая большая пробка шоу здесь IE9 + .
Роберт Коритник
19
Точно мне тоже нравится counts[num] = (counts[num] || 0) + 1. Таким образом, вам нужно всего лишь написать counts[num]дважды вместо трех раз в этой строке.
Робру
1
Это хороший ответ. Это легко абстрагируется в функцию, которая принимает массив и возвращает объект count.
Битсанд
Это верно для конкретного примера в вопросе, но ради googlers стоит отметить, что это не всегда безопасный метод для более широкого использования. Сохранение значений в виде ключей объекта для их подсчета означает, что вы приводите эти значения к строкам, а затем подсчитываете это значение. [5, "5"]просто скажу, у вас есть "5"два раза. Или подсчет экземпляров различных объектов просто скажет вам, что их много [object Object]. И т.д. и т.п.
Джимбо Джонни
Как я мог затем отфильтровать возвращаемый объект, чтобы он показывал мне число от нуля до максимума или от нуля до максимума
Райан Холтон
92
var a = [5, 5, 5, 2, 2, 2, 2, 2, 9, 4].reduce(function (acc, curr) {
  if (typeof acc[curr] == 'undefined') {
    acc[curr] = 1;
  } else {
    acc[curr] += 1;
  }

  return acc;
}, {});

// a == {2: 5, 4: 1, 5: 3, 9: 1}
adamse
источник
39
acc[curr] ? acc[curr]++ : acc[curr] = 1;
Pmandell
Спасибо, очень хорошее решение;) ... и получить массивы "ключ" и "значение":const keys = Object.keys(a); const values = Object.values(a);
ncenerar
80

Если вы используете подчеркивание или lodash, это самое простое:

_.countBy(array);

Такой что:

_.countBy([5, 5, 5, 2, 2, 2, 2, 2, 9, 4])
=> Object {2: 5, 4: 1, 5: 3, 9: 1}

Как указывалось другими, вы можете затем выполнить команду меню _.keys()и _.values()функции на результат , чтобы получить только уникальные номера, и их вхождения соответственно. Но по моему опыту, с оригинальным объектом гораздо проще иметь дело.

подкоренное выражение
источник
55

Не используйте два массива для результата, используйте объект:

a      = [5, 5, 5, 2, 2, 2, 2, 2, 9, 4];
result = { };
for(var i = 0; i < a.length; ++i) {
    if(!result[a[i]])
        result[a[i]] = 0;
    ++result[a[i]];
}

Тогда resultбудет выглядеть так:

{
    2: 5,
    4: 1,
    5: 3,
    9: 1
}
мю слишком коротка
источник
48

Как насчет опции ECMAScript2015.

const a = [5, 5, 5, 2, 2, 2, 2, 2, 9, 4];

const aCount = new Map([...new Set(a)].map(
    x => [x, a.filter(y => y === x).length]
));
aCount.get(5)  // 3
aCount.get(2)  // 5
aCount.get(9)  // 1
aCount.get(4)  // 1

Этот пример передает входной массив в Setконструктор, создавая коллекцию уникальных значений. Синтаксис распространения затем расширяет эти значения в новый массив таким образом , мы можем назвать mapи перевести это в двумерный массив из [value, count]пар - т.е. следующей структуры:

Array [
   [5, 3],
   [2, 5],
   [9, 1],
   [4, 1]
]

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

Map {
    5 => 3,
    2 => 5,
    9 => 1,
    4 => 1
}

Самое замечательное в Mapобъекте состоит в том, что он сохраняет типы данных - то есть aCount.get(5)будет возвращаться, 3но aCount.get("5")будет возвращаться undefined. Это также позволяет любому значению / типу действовать как ключ, означающий, что это решение также будет работать с массивом объектов.

эмиссар
источник
у вас есть случайно улучшенный ответ только для массива объектов? У меня возникли проблемы при попытке изменить его для массива объектов, где вы просто создаете новый массив / карту / набор, в котором удаляете дубликаты, и добавляете новое значение для объекта, скажем, с именем «duplicatedCount: value». мне удалось удалить дубликаты в моем массиве вложенных объектов из этого ответа stackoverflow.com/a/36744732
sharon gur
Setиспользует ссылки на объекты для уникальности и не предлагает API для сравнения «похожих» объектов. Если вы хотите использовать этот подход для такой задачи, вам понадобится некоторая промежуточная функция сокращения, которая гарантирует массив уникальных экземпляров. Это не самый эффективный, но я собрал небольшой пример здесь .
Эмиссар
Спасибо за ответ! но я на самом деле решил это немного по-другому. если вы видите ответ, который я добавил здесь stackoverflow.com/a/43211561/4474900 я привел пример того, что я сделал. это работает хорошо, у моего случая был сложный объект, который нужно сравнить. не знаю об эффективности моего решения
Шарон Гур
8
Это может использовать хорошие новые структуры данных, но имеет время выполнения в O ( ), в то время как здесь есть множество простых алгоритмов, которые решают это в O ( n ).
рафинесс
41

Я думаю, что это самый простой способ подсчета вхождений с одинаковым значением в массиве.

var a = [true, false, false, false];
a.filter(function(value){
    return value === false;
}).length
Дмитрий Козловский
источник
9
или a.filter(value => !value).lengthс новым синтаксисом js
t3chb0t
Не отвечает на вопрос.
Ry-
36

Однолинейное решение ES6. Так много ответов, используя объект в качестве карты, но я не вижу никого, кто использует настоящую карту

const map = arr.reduce((acc, e) => acc.set(e, (acc.get(e) || 0) + 1), new Map());

Используйте, map.keys()чтобы получить уникальные элементы

Используйте, map.values()чтобы получить вхождения

Используйте, map.entries()чтобы получить пары [элемент, частота]

var arr = [5, 5, 5, 2, 2, 2, 2, 2, 9, 4]

const map = arr.reduce((acc, e) => acc.set(e, (acc.get(e) || 0) + 1), new Map());

console.info([...map.keys()])
console.info([...map.values()])
console.info([...map.entries()])

corashina
источник
Современный Javascript получает лучшее из всех миров
воспламенитель
31

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

function count(arr) {
  return arr.reduce((prev, curr) => (prev[curr] = ++prev[curr] || 1, prev), {})
}

console.log(count(data))

Влад Безден
источник
4
Кто-нибудь захочет объяснить это (prev [curr] = ++ prev [curr] || 1, prev)?
Souljacker
6
Оператор запятой «вычисляет каждый из своих операндов (слева направо) и возвращает значение последнего операнда», поэтому он увеличивает значение prev [curr] (или инициализирует его до 1), а затем возвращает prev.
ChrisV
но является ли выход массивом?
Франческо
20

Если вы предпочитаете один лайнер.

arr.reduce(function(countMap, word) {countMap[word] = ++countMap[word] || 1;return countMap}, {});

Изменить (12.06.2015) : объяснение изнутри. countMap - это карта, которая отображает слово с его частотой, которую мы видим в анонимной функции. Что уменьшает, так это применяет функцию с аргументами в качестве всех элементов массива и countMap, передаваемых в качестве возвращаемого значения последнего вызова функции. Последний параметр ({}) является значением по умолчанию countMap для первого вызова функции.

rjalfa
источник
1
Вы должны объяснить это. это сделало бы его намного лучшим ответом, чтобы люди могли научиться использовать его в других случаях использования.
Эндрю Грот
Единственный лайнер, который просто удаляет разрыв строки, который обычно следует ;, {и }. ... ХОРОШО. Я думаю, что с этим определением одного лайнера мы можем написать «Игру жизни» Конвея как «лайнер».
Trincot
16

Версия ES6 должна быть намного проще (еще одно решение линии)

let arr = [5, 5, 5, 2, 2, 2, 2, 2, 9, 4];
let acc = arr.reduce((acc, val) => acc.set(val, 1 + (acc.get(val) || 0)), new Map());

console.log(acc);
// output: Map { 5 => 3, 2 => 5, 9 => 1, 4 => 1 }

Карта вместо простого Объекта помогает нам различать различные типы элементов, иначе все подсчеты основаны на строках

Уильям Люн
источник
8

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

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, если они доступны

демо: http://jsfiddle.net/dAaUU/

jhnstn
источник
8

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

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

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},{})

));

ESL
источник
Это было бы более читабельным, если бы вы использовали || 0:(r,k)=>{r[k]=(r[k]||0)+1;return r}
12Me21
Вы можете сделать что-нибудь в одной строке в JavaScript.
Ry-
И почему это плохо, @ Ry-?
ESL
Иногда это более понятно в нескольких строках, другое - в одной. Хотя это вопрос "вкуса".
ESL
Я имею в виду, что «в ES6 вы можете сделать это в одну строку» относится к каждому ответу, и вы также можете сделать это в ES5 в одну строку.
Ry-
5

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

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;
}
ElDoRado1239
источник
1
Вопрос задан для подсчета всех элементов.
Ry-
Хорошо, пропустил это. Должно быть исправлено сейчас.
ElDoRado1239
5

Итак, вот как я могу сделать это с некоторыми из новейших функций 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)
Гаррет Моцнер
источник
4
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};

Если вам все еще нужны два массива, вы можете использовать ответ вроде этого ...

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];
SoEzPz
источник
1
ES6 / 7 делает все это намного приятнее. MapВместо этого вы можете захотеть уменьшить значение до , так как это позволит избежать приведения типов к типу , который использует число в качестве ключа объекта (приведение в виде строки). const answer = array.reduce((a, e) => a.set(e, (a.get(e) || 0) + 1), new Map()).Вы можете получить answer.keys()для ключей, а answer.values()для значений в виде массивов. [...answer]даст вам большой массив со всеми ключами / значениями в виде 2d массивов.
Джош из Карибу
4

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

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

const count = arr.reduce((pre, cur) => (cur === 2) ? ++pre : pre, 0)
console.log(count) // 4

Томас Готвиг
источник
Не уверен, как одно число представляет количество каждого отдельного элемента массива, как заданный вопрос.
Ry-
4

Изменить 2020 : это довольно старый ответ (девять лет). Расширение нативного языка prototypeвсегда вызывает дискуссию . Хотя я думаю, что программист может свободно выбирать свой собственный стиль программирования, вот (более современный) подход к проблеме без расширения Array.prototype:

{
  // create array with some pseudo random values (1 - 5)
  const arr = Array.from({length: 100})
    .map( () => Math.floor(1 + Math.random() * 5) );
  // frequencies using a reducer
  const arrFrequencies = arr.reduce((acc, value) => 
      ({ ...acc, [value]: acc[value] + 1 || 1}), {} )
  console.log(`Value 4 occurs ${arrFrequencies[4]} times in arrFrequencies`);

  // bonus: restore Array from frequencies
  const arrRestored = Object.entries(arrFrequencies)
    .reduce( (acc, [key, value]) => acc.concat(Array(value).fill(+key)), [] );
  console.log(arrRestored.join());  
}
.as-console-wrapper { top: 0; max-height: 100% !important; }

Старый (2011) ответ: вы могли бы расширить Array.prototype, как это:

KooiInc
источник
2

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

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.

Michal
источник
2

Решение с использованием карты с O (n) сложностью по времени.

var arr = [2, 2, 2, 2, 2, 4, 5, 5, 5, 9];

const countOccurrences = (arr) => {
    const map = {};
    for ( var i = 0; i < arr.length; i++ ) {
        map[arr[i]] = ~~map[arr[i]] + 1;
    }
    return map;
}

Демо: http://jsfiddle.net/simevidas/bnACW/

Сардоржон Ваккосов
источник
Мое приветствие к вам, это работает как масло с O (n) сложностью времени
Вишал Шетти
1

Существует гораздо лучший и простой способ, которым мы можем сделать это, используя ramda.js. Пример кода здесь

const ary = [5, 5, 5, 2, 2, 2, 2, 2, 9, 4]; R.countBy(r=> r)(ary) countBy документация находится в документации

Эшвар Прасад Ядданапуди
источник
1

Используя MAP, вы можете иметь 2 массива в выходных данных: один содержит вхождения, а другой - количество вхождений.

const dataset = [2,2,4,2,6,4,7,8,5,6,7,10,10,10,15];
let values = [];
let keys = [];

var mapWithOccurences = dataset.reduce((a,c) => {
  if(a.has(c)) a.set(c,a.get(c)+1);
  else a.set(c,1);
  return a;
}, new Map())
.forEach((value, key, map) => {
  keys.push(key);
  values.push(value);
});


console.log(keys)
console.log(values)

Melchia
источник
0

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

<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>
Воутер ван Нифтерик
источник
0

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

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;
}
Аамир Африди
источник
0

Я решал аналогичную проблему на codewars и разработал следующее решение, которое сработало для меня.

Это дает наибольшее количество целых в массиве, а также само целое число. Я думаю, что это может быть применено и к строковому массиву.

Чтобы правильно отсортировать строки, удалите function(a, b){return a-b}изнутри sort()часть

function mostFrequentItemCount(collection) {
    collection.sort(function(a, b){return a-b});
    var i=0;
    var ans=[];
    var int_ans=[];
    while(i<collection.length)
    {
        if(collection[i]===collection[i+1])
        {
            int_ans.push(collection[i]);
        }
        else
        {
            int_ans.push(collection[i]);
            ans.push(int_ans);
            int_ans=[];
        }
        i++;
    }

    var high_count=0;
    var high_ans;

    i=0;
    while(i<ans.length)
    {
        if(ans[i].length>high_count)
        {
            high_count=ans[i].length;
            high_ans=ans[i][0];
        }
        i++;
    }
    return high_ans;
}
Варун Упадхяй
источник
0

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

var big_array = [
  { name: "Pineapples", quantity: 3 },
  { name: "Pineapples", quantity: 1 },
  { name: "Bananas", quantity: 1 },
  { name: "Limes", quantity: 1 },
  { name: "Bananas", quantity: 1 },
  { name: "Pineapples", quantity: 2 },
  { name: "Pineapples", quantity: 1 },
  { name: "Bananas", quantity: 1 },
  { name: "Bananas", quantity: 1 },
  { name: "Bananas", quantity: 5 },
  { name: "Coconuts", quantity: 1 },
  { name: "Lemons", quantity: 2 },
  { name: "Oranges", quantity: 1 },
  { name: "Lemons", quantity: 1 },
  { name: "Limes", quantity: 1 },
  { name: "Grapefruit", quantity: 1 },
  { name: "Coconuts", quantity: 5 },
  { name: "Oranges", quantity: 6 }
];

function countThem() {
  var names_array = [];
  for (var i = 0; i < big_array.length; i++) {
    names_array.push( Object.assign({}, big_array[i]) );
  }

  function outerHolder(item_array) {
    if (item_array.length > 0) {
      var occurrences = [];
      var counter = 0;
      var bgarlen = item_array.length;
      item_array.sort(function(a, b) { return (a.name > b.name) ? 1 : ((b.name > a.name) ? -1 : 0); });

      function recursiveCounter() {
        occurrences.push(item_array[0]);
        item_array.splice(0, 1);
        var last_occurrence_element = occurrences.length - 1;
        var last_occurrence_entry = occurrences[last_occurrence_element].name;
        var occur_counter = 0;
        var quantity_counter = 0;
        for (var i = 0; i < occurrences.length; i++) {
          if (occurrences[i].name === last_occurrence_entry) {
            occur_counter = occur_counter + 1;
            if (occur_counter === 1) {
              quantity_counter = occurrences[i].quantity;
            } else {
              quantity_counter = quantity_counter + occurrences[i].quantity;
            }
          }
        }

        if (occur_counter > 1) {
          var current_match = occurrences.length - 2;
          occurrences[current_match].quantity = quantity_counter;
          occurrences.splice(last_occurrence_element, 1);
        }

        counter = counter + 1;

        if (counter < bgarlen) {
          recursiveCounter();
        }
      }

      recursiveCounter();

      return occurrences;
    }
  }
  alert(JSON.stringify(outerHolder(names_array)));
}
nate_js
источник
0
function countOcurrences(arr){
    return arr.reduce((aggregator, value, index, array) => {
      if(!aggregator[value]){
        return aggregator = {...aggregator, [value]: 1};  
      }else{
        return aggregator = {...aggregator, [value]:++aggregator[value]};
      }
    }, {})
}
Хосе Сальгадо
источник
Чрезвычайно расточительно копировать объект каждый раз. Создает квадратичный наихудший случай, когда он может быть линейным.
Ry-
0
var aa = [1,3,5,7,3,2,4,6,8,1,3,5,5,2,0,6,5,9,6,3,5,2,5,6,8];
var newArray = {};
for(var element of aa){
  if(typeof newArray[element] === 'undefined' || newArray[element] === null){
    newArray[element] = 1;
  }else{
    newArray[element] +=1;
  }
}

for ( var element in newArray){
  console.log( element +" -> "+ newArray[element]);
}
Дилрадж Сингх
источник
0

Этому вопросу более 8 лет, и многие, многие ответы на самом деле не учитывают ES6 и его многочисленные преимущества.

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

Если вам просто нужен «счетчик» для определенных типов данных, а отправной точкой является массив (поэтому я предполагаю, что вы хотите упорядоченный список и воспользоваться множеством свойств и методов, предлагаемых массивами), вы можете просто перебрать массив1 и заполнить массив2 со значениями и количеством вхождений для этих значений, найденных в массиве1.

Так просто, как, что.

Пример простого класса SimpleCounter (ES6) для объектно-ориентированного программирования и объектно-ориентированного проектирования

class SimpleCounter { 

    constructor(rawList){ // input array type
        this.rawList = rawList;
        this.finalList = [];
    }

    mapValues(){ // returns a new array

        this.rawList.forEach(value => {
            this.finalList[value] ? this.finalList[value]++ : this.finalList[value] = 1;
        });

        this.rawList = null; // remove array1 for garbage collection

        return this.finalList;

    }

}

module.exports = SimpleCounter;
Rags2riches
источник
Застревание функции в классе без причины не делает ее объектно-ориентированной, у finalListнее нет причины быть массивом, и это не имеет никаких преимуществ по сравнению с ее правильной работой.
Ry-
-1

Вот классический метод старой школы для подсчета массивов.

var arr = [5, 5, 5, 2, 2, 2, 2, 2, 9, 4];
var counted = [], count = [];
var i = 0, j = 0, k = 0;
while (k < arr.length) {
    if (counted.indexOf(arr[k]) < 0) {
        counted[i] = arr[k];
        count[i] = 0;
        for (j = 0; j < arr.length; j++) {
            if (counted[i] == arr[j]) {
                count[i]++;
            }
        }
        i++;
    } else {
        k++;
    }
}

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

MangoPapa7
источник