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


218

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

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

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

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

5, 2, 9, 4

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

3, 5, 1, 1

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

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

Спасибо :)


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}

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()])


Современный 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 для первого вызова функции.


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/


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

));


Это было бы более читабельным, если бы вы использовали || 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;
}

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

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, как это:


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.


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

Используя 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)


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

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;

Застревание функции в классе без причины не делает ее объектно-ориентированной, у 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++;
    }
}

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

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.