Contando as ocorrências / frequência dos elementos da matriz


215

Em Javascript, estou tentando pegar uma matriz inicial de valores numéricos e contar os elementos dentro dela. Idealmente, o resultado seria duas novas matrizes, a primeira especificando cada elemento exclusivo e a segunda contendo o número de vezes que cada elemento ocorre. No entanto, estou aberto a sugestões sobre o formato da saída.

Por exemplo, se a matriz inicial fosse:

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

Em seguida, duas novas matrizes seriam criadas. O primeiro conteria o nome de cada elemento exclusivo:

5, 2, 9, 4

O segundo conteria o número de vezes que esse elemento ocorreu na matriz inicial:

3, 5, 1, 1

Como o número 5 ocorre três vezes na matriz inicial, o número 2 ocorre cinco vezes e 9 e 4 aparecem uma vez.

Eu procurei muito por uma solução, mas nada parece funcionar, e tudo o que eu tentei acabou sendo ridiculamente complexo. Qualquer ajuda seria apreciada!

Obrigado :)


8
Se tudo o que você precisava era para ver se um valor aparece apenas uma vez (em vez de duas ou mais vezes), você poderia usarif (arr.indexOf(value) == arr.lastIndexOf(value))
Rodrigo

1
Podemos usar ramda.jspara conseguir isso da maneira mais fácil. const ary = [5, 5, 5, 2, 2, 2, 2, 2, 9, 4]; R.countBy(r=> r)(ary)
Eshwar Prasad Yaddanapudi 4/17/17

arr.filter(x => x===5).lengthretornaria 3para indicar que há '3' cinco na matriz.
noobninja 15/06

Respostas:


94

Aqui está:

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

Demonstração ao vivo: http://jsfiddle.net/simevidas/bnACW/

Nota

Isso altera a ordem da matriz de entrada original usando Array.sort


24
tem efeito colateral de ordenar o array (efeitos colaterais são maus), também a classificação é O(N log(N))ea elegância ganho não vale a pena
ninjagecko

1
@ ninja Qual outra resposta você prefere?
Šime Vidas

Na ausência de uma primitiva de alto nível agradável de uma biblioteca de terceiros, eu normalmente implementaria isso como a reduceresposta. Eu estava prestes a enviar uma resposta antes de ver que ela já existia. No entanto, a counts[num] = counts[num] ? counts[num]+1 : 1resposta também funciona (equivalente à if(!result[a[i]])result[a[i]]=0resposta, que é mais elegante, mas menos fácil de ler); essas respostas podem ser modificadas para usar uma versão "mais agradável" do loop for, talvez um loop for de terceiros, mas eu meio que ignorei isso, já que os loops for baseados em índice padrão são, infelizmente, o padrão.
Ninjagecko 25/05

2
@ Ninja Eu concordo. Essas respostas são melhores. Infelizmente, não posso cancelar minha resposta.
Šime Vidas

Para pequenas matrizes, classificá-lo no local pode ser mais rápido do que criar um array associativo.
Quant_dev 29/09/17

219

Você pode usar um objeto para armazenar os resultados:

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

Portanto, agora seu objeto de contagem pode lhe dizer qual é a contagem para um número específico:

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

Se você deseja obter uma matriz de membros, basta usar as keys()funções

keys(counts); // returns ["5", "2", "9", "4"]

3
Vale ressaltar que essa Object.keys()função é suportada apenas no IE9 +, FF4 +, SF5 +, CH6 +, mas o Opera não a suporta. Eu acho que a maior rolha de show aqui é o IE9 + .
Robert Koritnik 28/07

19
Da mesma forma, eu também gosto counts[num] = (counts[num] || 0) + 1. Dessa forma, você só precisa escrever counts[num]duas vezes em vez de três vezes nessa linha.
robru

1
Esta é uma boa resposta. Isso é facilmente abstraído para uma função que aceita uma matriz e retorna um objeto 'count'.
bitsand 23/02

Isso é verdade para o exemplo específico da pergunta, mas, para os googlers, vale ressaltar que essa nem sempre é uma técnica segura para uso mais amplo. Armazenar os valores como chaves de objeto para contá-los significa que você está convertendo esses valores em cadeias e depois contando esse valor. [5, "5"]dirá simplesmente que você tem "5"duas vezes. Ou contar instâncias de alguns objetos diferentes apenas indica que há muitos [object Object]. Etc. etc.
Jimbo Jonny

Como eu poderia então filtrar o objeto retornado para me mostrar a contagem mais alta para a mais baixa ou mais baixa para a mais alta num número
Ryan Holton

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

Obrigado, solução muito boa;) ... e para obter as matrizes "chave" e "valor":const keys = Object.keys(a); const values = Object.values(a);
ncenerar

79

Se você estiver usando sublinhado ou lodash, é a coisa mais simples a fazer:

_.countBy(array);

De tal modo que:

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

Conforme indicado por outras pessoas, você pode executar as funções _.keys()e _.values()no resultado para obter apenas os números exclusivos e suas ocorrências, respectivamente. Mas, na minha experiência, o objeto original é muito mais fácil de lidar.


55

Não use duas matrizes para o resultado, use um objeto:

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

Então resultserá parecido com:

{
    2: 5,
    4: 1,
    5: 3,
    9: 1
}

47

Que tal uma opção 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

Este exemplo passa a matriz de entrada para o Setconstrutor, criando uma coleção de valores exclusivos . A sintaxe de dispersão expande esses valores em uma nova matriz, para que possamos chamar mape traduzir isso em uma matriz bidimensional de [value, count]pares - ou seja, a seguinte estrutura:

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

A nova matriz é então passada para o Mapconstrutor, resultando em um objeto iterável :

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

O melhor de um Mapobjeto é que ele preserva tipos de dados - ou seja aCount.get(5), retornará, 3mas aCount.get("5")retornará undefined. Ele também permite que qualquer valor / tipo atue como uma chave, o que significa que esta solução também funcionará com uma matriz de objetos.


você tem por acaso uma resposta melhorada apenas para uma matriz de objetos? estou tendo problemas para tentar modificá-lo para uma matriz de objetos, onde você apenas cria uma nova matriz / mapa / conjunto na qual remove duplicatas e adiciona um novo valor ao objeto, digamos chamado "duplicatedCount: value". i conseguiu remover duplicatas em minha matriz objetos aninhados a partir desta resposta stackoverflow.com/a/36744732
sharon gur

Setusa referências de objeto para exclusividade e não oferece API para comparação de objetos "semelhantes" . Se você deseja usar essa abordagem para essa tarefa, precisará de alguma função de redução intermediária que garanta uma matriz de instâncias exclusivas. Não é o mais eficiente, mas reuni um exemplo rápido aqui .
emissário

Obrigado pela resposta! mas na verdade resolvi um pouco diferente. se você pode ver a resposta que adicionei aqui stackoverflow.com/a/43211561/4474900, dei exemplo do que fiz. funciona bem, meu caso tinha um objeto complexo que precisava ser comparado. não sei sobre a eficiência da minha solução embora
sharon gur

8
Isso pode usar boas novas estruturas de dados, mas possui tempo de execução em O ( ), enquanto há muitos algoritmos simples aqui que o resolvem em O ( n ).
raphinesse

41

Eu acho que esta é a maneira mais simples de como contar ocorrências com o mesmo valor na matriz.

var a = [true, false, false, false];
a.filter(function(value){
    return value === false;
}).length

9
ou a.filter(value => !value).lengthcom a nova sintaxe js
t3chb0t

Não responde a pergunta.
Ry-

34

Solução ES6 de uma linha. Tantas respostas usando o objeto como um mapa, mas não vejo ninguém usando um mapa real

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

Use map.keys()para obter elementos exclusivos

Use map.values()para obter as ocorrências

Use map.entries()para obter os pares [elemento, frequência]

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


Modern Javascript obtém o melhor de todos os mundos
Igniter

29

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


3
Alguém gostaria de explicar isso (prev [curr] = ++ prev [curr] || 1, prev)?
Souljacker 14/05

5
O operador de vírgula “avalia cada um de seus operandos (da esquerda para a direita) e retorna o valor do último operando”; portanto, isso incrementa o valor de prev [curr] (ou inicializa para 1), depois retorna prev.
ChrisV

mas a saída é uma matriz?
Francesco

20

Se você prefere um único revestimento.

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

Editar (12/06/2015) : a explicação de dentro para fora. countMap é um mapa que mapeia uma palavra com sua frequência, e podemos ver a função anônima. O que reduz é aplicar a função com argumentos como todos os elementos da matriz e countMap sendo passados ​​como o valor de retorno da última chamada de função. O último parâmetro ({}) é o valor padrão de countMap para a primeira chamada de função.


1
Você deveria explicar isso. isso tornaria uma resposta muito melhor para que as pessoas aprendam como usá-lo em outros casos de uso.
Andrew Grothe

Um liner único que apenas remove a quebra de linha que normalmente seguiria ;, {e }. ... ESTÁ BEM. Penso que, com essa definição de uma linha, podemos escrever o Jogo da Vida de Conway como um "delineador".
trincot

16

A versão ES6 deve ser muito mais simplificada (outra solução de uma linha)

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 }

Um mapa em vez de um objeto simples, ajudando-nos a distinguir diferentes tipos de elementos, ou então todas as contagens são baseadas em cadeias


8

Se você estiver usando sublinhado, poderá seguir a rota funcional

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

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

então sua primeira matriz é

_.keys(results)

e a segunda matriz é

_.values(results)

a maior parte disso será padronizada para funções JavaScript nativas, se estiverem disponíveis

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


8

Com base nas respostas de @adamse e @pmandell (que eu votei), no ES6, você pode fazer isso em uma linha :

  • Edição de 2017 : uso ||para reduzir o tamanho do código e torná-lo mais legível.

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

));


Pode ser usado para contar caracteres :

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

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

));


Seria mais legível se você usasse || 0:(r,k)=>{r[k]=(r[k]||0)+1;return r}
12Me21

Você pode fazer qualquer coisa em uma linha em JavaScript.
Ry-

E por que isso é ruim, @ Ry-?
ESL

Às vezes é mais claro em várias linhas, outro é mais claro em uma linha. No entanto, é uma questão de "gosto".
ESL

Quero dizer "no ES6, você pode fazer isso em uma linha" se aplica a todas as respostas, e você também pode fazer isso no ES5 em uma linha.
Ry-

5

Aqui está apenas algo leve e fácil para os olhos ...

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

Edit: E desde que você deseja todas as ocorrências ...

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
A pergunta pedia contagens de todos os elementos.
Ry-

Ok, senti falta disso. Deve ser corrigido agora.
ElDoRado1239

5

Então, aqui está como eu faria isso com alguns dos mais recentes recursos javascript:

Primeiro, reduza a matriz para uma Mapdas contagens:

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

Usando a Map, sua matriz inicial pode conter qualquer tipo de objeto e as contagens estarão corretas. Sem a Map, alguns tipos de objetos fornecem contagens estranhas. Consulte os Mapdocumentos para obter mais informações sobre as diferenças.

Isso também pode ser feito com um objeto se todos os seus valores forem símbolos, números ou seqüências de caracteres:

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

Ou um pouco mais sofisticado de uma maneira funcional, sem mutação, usando a sintaxe da desestruturação e da propagação do objeto:

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

Nesse ponto, você pode usar o Mapobjeto ou para suas contagens (e o mapa é diretamente iterável, diferente de um objeto), ou convertê-lo em duas matrizes.

Para o Map:

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

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

Ou para o objeto:

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

Se você ainda deseja duas matrizes, pode usar uma resposta como esta ...

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

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

Ou se você quiser que Núms únicos sejam números

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

1
es6 / 7 torna tudo isso muito melhor. Você também pode querer reduzir para um Map, pois isso evitará a transmissão tipográfica que o uso de um número como chave de objeto (conversão como string) faz. const answer = array.reduce((a, e) => a.set(e, (a.get(e) || 0) + 1), new Map()).Você pode obter answer.keys()as chaves e answer.values()os valores como matrizes. [...answer]fornecerá uma grande matriz com todas as chaves / valores como matrizes 2D.
Josh de Qaribou

4

Solução ES6 com redução (fixa):

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

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


Não sei como um número representa as contagens de cada elemento distinto da matriz, como a pergunta feita.
Ry-

4

Edit 2020 : esta é uma resposta bastante antiga (nove anos). Estender o nativo prototypesempre gerará discussão . Embora eu ache que o programador é livre para escolher seu próprio estilo de programação, aqui está uma abordagem (mais moderna) do problema sem estender 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; }

A resposta antiga (2011): você poderia estender Array.prototype, assim:


2

Minha solução com ramda:

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)

Link para REPL.


2

Solução usando um mapa com O (n) complexidade de tempo.

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

Demonstração: http://jsfiddle.net/simevidas/bnACW/


Meu voto positivo para você, isso funciona como manteiga com complexidade de tempo O (n)
Vishal Shetty


1

Usando o MAP, você pode ter 2 matrizes na saída: uma contendo as ocorrências e a outra contendo o número de ocorrências.

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

Confira o código abaixo.

<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

Tente o seguinte:

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

Eu estava resolvendo um problema semelhante nas codewars e desenvolvi a seguinte solução que funcionou para mim.

Isso fornece a contagem mais alta de um número inteiro em uma matriz e também o próprio número inteiro. Eu acho que também pode ser aplicado ao array de strings.

Para classificar corretamente as cordas, remova o function(a, b){return a-b}de dentro da sort()parte

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

Aqui está uma maneira de contar ocorrências dentro de uma matriz de objetos. Ele também coloca o conteúdo da primeira matriz dentro de uma nova matriz para classificar os valores para que a ordem na matriz original não seja interrompida. Em seguida, uma função recursiva é usada para percorrer cada elemento e contar a propriedade de quantidade de cada objeto dentro da matriz.

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

Extremamente desperdício para copiar o objeto todas as vezes. Cria um pior caso quadrático quando poderia ser linear.
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

Esta pergunta tem mais de 8 anos e muitas respostas não levam realmente o ES6 e suas inúmeras vantagens em consideração.

Talvez seja ainda mais importante pensar nas consequências de nosso código para gerenciamento de coleta / memória de lixo sempre que criamos matrizes adicionais, fazemos cópias duplas ou triplas de matrizes ou mesmo convertemos matrizes em objetos. Essas são observações triviais para pequenas aplicações, mas se a escala é um objetivo de longo prazo, pense nelas minuciosamente.

Se você só precisa de um "contador" para tipos de dados específicos e o ponto de partida é uma matriz (suponho que você queira uma lista ordenada e tire proveito das muitas propriedades e métodos que as matrizes oferecem), basta simplesmente percorrer a matriz1 e preencher array2 com os valores e o número de ocorrências para esses valores encontrados no array1.

Tão simples como isso.

Exemplo de classe simples SimpleCounter (ES6) para Programação Orientada a Objetos e Design Orientado a Objetos

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;

Colocar uma função em uma classe sem motivo não a orienta a objetos, finalListnão tem motivo para ser uma matriz e isso não tem vantagens em fazê-lo corretamente.
Ry-

-1

Aqui está um método clássico da velha escola para contar matrizes.

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

Você pode classificá-lo primeiro se desejar um resultado alfabético, mas se desejar preservar a ordem em que os dados foram inseridos, tente fazer isso. Os loops aninhados podem ser um pouco mais lentos que alguns dos outros métodos nesta página.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.