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

Jack W
fonte
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

Šime Vidas
fonte
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"]
tipo de
fonte
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}
adamse
fonte
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.

radicand
fonte
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
}
mu é muito curto
fonte
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.

Emissário
fonte
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
Dmytro Kozlovskyi
fonte
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()])

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

Vlad Bezden
fonte
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.

rjalfa
fonte
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

William Leung
fonte
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/

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

));

ESL
fonte
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;
}
ElDoRado1239
fonte
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)
Garrett Motzner
fonte
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];
SoEzPz
fonte
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

Thomas Gotwig
fonte
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:

KooiInc
fonte
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.

Michal
fonte
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/

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

Existe uma maneira muito melhor e fácil de fazer isso usando ramda.js. Exemplo de código aqui

const ary = [5, 5, 5, 2, 2, 2, 2, 2, 9, 4]; R.countBy(r=> r)(ary) A documentação countBy está na documentação

Eshwar Prasad Yaddanapudi
fonte
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)

Melchia
fonte
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>
Wouter van Nifterick
fonte
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;
}
Aamir Afridi
fonte
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;
}
Varun Upadhyay
fonte
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)));
}
nate_js
fonte
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]};
      }
    }, {})
}
José Salgado
fonte
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]);
}
Dilraj Singh
fonte
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;
rags2riches
fonte
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.

MangoPapa7
fonte