Contando las ocurrencias / frecuencia de los elementos de la matriz

215

En Javascript, estoy tratando de tomar una matriz inicial de valores numéricos y contar los elementos dentro de ella. Idealmente, el resultado sería dos nuevas matrices, la primera que especifica cada elemento único y la segunda que contiene el número de veces que ocurre cada elemento. Sin embargo, estoy abierto a sugerencias sobre el formato de la salida.

Por ejemplo, si la matriz inicial era:

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

Luego se crearían dos nuevas matrices. El primero contendría el nombre de cada elemento único:

5, 2, 9, 4

El segundo contendría la cantidad de veces que ese elemento ocurrió en la matriz inicial:

3, 5, 1, 1

Debido a que el número 5 aparece tres veces en la matriz inicial, el número 2 aparece cinco veces y 9 y 4 aparecen una vez.

He buscado mucho una solución, pero nada parece funcionar, y todo lo que he probado ha resultado ser ridículamente complejo. ¡Cualquier ayuda sería apreciada!

Gracias :)

Jack W
fuente
8
Si todo lo que necesitara fuera ver si un valor aparece solo una vez (en lugar de dos o más veces), podría usarif (arr.indexOf(value) == arr.lastIndexOf(value))
Rodrigo
1
Podemos usar ramda.jspara lograr esto de la manera fácil. const ary = [5, 5, 5, 2, 2, 2, 2, 2, 9, 4]; R.countBy(r=> r)(ary)
Eshwar Prasad Yaddanapudi
arr.filter(x => x===5).lengthvolvería 3a indicar que hay '3' cinco en la matriz.
noobninja

Respuestas:

94

Aqui tienes:

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

Demostración en vivo: http://jsfiddle.net/simevidas/bnACW/

Nota

Esto cambia el orden de la matriz de entrada original usando Array.sort

Šime Vidas
fuente
24
tiene efecto secundario de la clasificación de la matriz (efectos secundarios son severos), también es la clasificación O(N log(N))y la ganancia elegancia no vale la pena
ninjagecko
1
@ninja ¿Qué otra respuesta prefieres?
Šime Vidas
En ausencia de una buena primitiva de alto nivel de una biblioteca de terceros, normalmente implementaría esto como la reducerespuesta. Estaba a punto de presentar tal respuesta antes de ver que ya existía. Sin embargo, la counts[num] = counts[num] ? counts[num]+1 : 1respuesta también funciona (equivalente a la if(!result[a[i]])result[a[i]]=0respuesta, que es más elegante pero menos fácil de leer); estas respuestas pueden modificarse para usar una versión "más agradable" del bucle for, quizás un for-loop de terceros, pero ignoré eso ya que los bucles for basados ​​en índices estándar son lamentablemente los predeterminados.
ninjagecko
2
@ninja Estoy de acuerdo. Esas respuestas son mejores. Lamentablemente no puedo dejar de aceptar mi propia respuesta.
Šime Vidas
Para matrices pequeñas, ordenarlas en el lugar puede ser más rápido que crear una matriz asociativa.
quant_dev
219

Puede usar un objeto para guardar los 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]);

Entonces, ahora su objeto de conteo puede decirle cuál es el conteo para un número particular:

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

Si desea obtener una variedad de miembros, simplemente use las keys()funciones

keys(counts); // returns ["5", "2", "9", "4"]
tipo de
fuente
3
Cabe señalar que esa Object.keys()función solo es compatible con IE9 +, FF4 +, SF5 +, CH6 +, pero Opera no lo admite. Creo que el mayor show stopper aquí es IE9 + .
Robert Koritnik
19
Del mismo modo, también me gusta counts[num] = (counts[num] || 0) + 1. De esa manera, solo tiene que escribir counts[num]dos veces en lugar de tres veces en esa línea allí.
robru
1
Esta es una buena respuesta. Esto se abstrae fácilmente en una función que acepta una matriz y devuelve un objeto 'recuento'.
bitsand
Esto es cierto para el ejemplo específico en la pregunta, pero por el bien de los googlers vale la pena señalar que esta no siempre es una técnica segura para un uso más amplio. Almacenar los valores como claves de objeto para contarlos significa que está convirtiendo esos valores en cadenas y luego contando ese valor. [5, "5"]simplemente dirá que tienes "5"dos veces. O contar instancias de algunos objetos diferentes solo te dirá que hay muchos [object Object]. Etc. etc.
Jimbo Jonny
¿Cómo podría filtrar el objeto devuelto para mostrarme de mayor a menor, o de menor a mayor número de números?
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
fuente
39
acc[curr] ? acc[curr]++ : acc[curr] = 1;
pmandell
Gracias, muy buena solución;) ... y para obtener las matrices de "clave" y "valor":const keys = Object.keys(a); const values = Object.values(a);
ncenerar
79

Si usa subrayado o lodash, esto es lo más simple:

_.countBy(array);

Tal que:

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

Como señalaron otros, puede ejecutar las funciones _.keys()y _.values()en el resultado para obtener solo los números únicos y sus ocurrencias, respectivamente. Pero en mi experiencia, el objeto original es mucho más fácil de manejar.

radicando
fuente
55

No use dos matrices para el resultado, use un 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]];
}

Entonces resultse verá así:

{
    2: 5,
    4: 1,
    5: 3,
    9: 1
}
mu es demasiado corto
fuente
47

¿Qué tal una opción 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 ejemplo pasa la matriz de entrada al Setconstructor creando una colección de valores únicos . La sintaxis extendida luego expande estos valores en una nueva matriz para que podamos llamar mapy traducir esto en una matriz bidimensional de [value, count]pares, es decir, la siguiente estructura:

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

La nueva matriz se pasa al Mapconstructor dando como resultado un objeto iterable :

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

Lo mejor de un Mapobjeto es que conserva los tipos de datos, es decir aCount.get(5), volverá 3pero aCount.get("5")volverá undefined. También permite que cualquier valor / tipo actúe como clave, lo que significa que esta solución también funcionará con una variedad de objetos.

Emisario
fuente
¿tiene por casualidad una respuesta mejorada de esto solo para una matriz de objetos? Tengo problemas para tratar de modificarlo para una matriz de objetos, donde solo crea una nueva matriz / mapa / conjunto en el que elimina los duplicados, y agrega un nuevo valor para el objeto, digamos llamado "duplicatedCount: value". logré eliminar duplicados en mi matriz de objetos anidados de esta respuesta stackoverflow.com/a/36744732
sharon gur
Setusa referencias de objetos para la unicidad y no ofrece API para comparar objetos "similares" . Si desea utilizar este enfoque para tal tarea, necesitaría alguna función de reducción intermedia que garantice una variedad de instancias únicas. No es el más eficiente, pero preparé un ejemplo rápido aquí .
Emisario
¡Gracias por la respuesta! pero en realidad lo resolví un poco diferente. si puedes ver la respuesta que agregué aquí stackoverflow.com/a/43211561/4474900 di ejemplo de lo que hice. funciona bien, mi caso tenía un objeto complejo que necesitaba ser comparado. sin embargo
sharon gur
8
Esto podría usar nuevas estructuras de datos agradables, pero tiene tiempo de ejecución en O ( ), mientras que aquí hay muchos algoritmos simples que lo resuelven en O ( n ).
raphinesse
41

Creo que esta es la forma más simple de contar las ocurrencias con el mismo valor en la matriz.

var a = [true, false, false, false];
a.filter(function(value){
    return value === false;
}).length
Dmytro Kozlovskyi
fuente
99
o a.filter(value => !value).lengthcon la nueva sintaxis js
t3chb0t
No responde la pregunta.
Ry-
34

Solución ES6 de una línea. Tantas respuestas usando el objeto como mapa pero no puedo ver a nadie usando un mapa real

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

Úselo map.keys()para obtener elementos únicos

Use map.values()para obtener los sucesos

Use map.entries()para obtener los pares [elemento, frecuencia]

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
fuente
Javascript moderno obtiene lo mejor de todos los 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
fuente
3
¿A alguien le gustaría explicar esto (prev [curr] = ++ prev [curr] || 1, prev)?
Souljacker
55
El operador de coma "evalúa cada uno de sus operandos (de izquierda a derecha) y devuelve el valor del último operando", por lo que esto incrementa el valor de prev [curr] (o lo inicializa a 1), luego devuelve prev.
ChrisV
pero es la salida una matriz?
Francesco
20

Si prefiere un solo revestimiento.

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

Editar (6/12/2015) : La explicación de adentro hacia afuera. countMap es un mapa que mapea una palabra con su frecuencia, en la cual podemos ver la función anónima. Lo que reduce es aplicar la función con argumentos como todos los elementos de la matriz y countMap que se pasa como el valor de retorno de la última llamada a la función. El último parámetro ({}) es el valor predeterminado de countMap para la primera llamada de función.

rjalfa
fuente
1
Deberías explicar esto. eso sería una respuesta mucho mejor para que las personas puedan aprender cómo usarlo en otros casos de uso.
Andrew Grothe
Un solo revestimiento que simplemente elimina el salto de línea que generalmente seguiría ;, {y }. ... OKAY. Creo que con esa definición de un trazador de líneas podemos escribir El juego de la vida de Conway como un "trazador de líneas".
Trincot
16

La versión ES6 debería ser mucho más simple (otra solución de una línea)

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 }

Un mapa en lugar de un objeto simple que nos ayuda a distinguir diferentes tipos de elementos, o de lo contrario todo el conteo se basa en cadenas

William Leung
fuente
8

Si está usando guión bajo, puede seguir la ruta 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] })))

entonces tu primer arreglo es

_.keys(results)

y la segunda matriz es

_.values(results)

la mayor parte de esto usará de forma predeterminada las funciones nativas de JavaScript si están disponibles

demostración: http://jsfiddle.net/dAaUU/

jhnstn
fuente
8

Según la respuesta de @adamse y @pmandell (que voté positivamente ), en ES6 puede hacerlo en una línea :

  • Edición de 2017 : uso ||para reducir el tamaño del código y hacerlo más legible.

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

));


Se puede usar para contar caracteres :

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

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

));

ESL
fuente
Sería más legible si || 0(r,k)=>{r[k]=(r[k]||0)+1;return r}
usaras
Puedes hacer cualquier cosa en una línea en JavaScript.
Ry-
¿Y por qué es algo malo, @ Ry-?
ESL
A veces es más claro en varias líneas, otro es más claro en una línea. Aunque es una cuestión de "gusto".
ESL
Quiero decir que "en ES6 puedes hacerlo en una línea" se aplica a cada respuesta, y también puedes hacerlo en ES5 en una línea.
Ry-
5

Aquí hay algo ligero y fácil para los ojos ...

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

Editar: Y como quieres todas las ocurrencias ...

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
fuente
1
La pregunta pedía recuentos de todos los elementos.
Ry-
Ok, me perdí eso. Debería arreglarse ahora.
ElDoRado1239
5

Así que así es como lo haría con algunas de las características más nuevas de JavaScript:

Primero, reduzca la matriz a uno Mapde los recuentos:

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

Al usar a Map, su matriz inicial puede contener cualquier tipo de objeto, y los recuentos serán correctos. Sin a Map, algunos tipos de objetos te darán recuentos extraños. Consulte los Mapdocumentos para obtener más información sobre las diferencias.

Esto también se podría hacer con un objeto si todos sus valores son símbolos, números o cadenas:

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

O un poco más elegante de una manera funcional sin mutación, utilizando la sintaxis de desestructuración y propagación de objetos:

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

En este punto, puede usar el Mapobjeto o para sus recuentos (y el mapa es directamente iterable, a diferencia de un objeto), o convertirlo en dos matrices.

Para el Map:

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

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

O para el 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
fuente
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};

Si todavía quieres dos matrices, entonces podrías usar una respuesta 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];

O si quieres números únicos para ser números

var uniqueNums = Object.keys(answer).map(key => +key);
// uniqueNums => [2, 4, 5, 9];
SoEzPz
fuente
1
es6 / 7 hace que todo esto sea mucho más agradable. Es posible que también desee reducir a a Map, ya que evitará el encasillamiento que hace el uso de un número como clave de objeto (conversión como cadena). const answer = array.reduce((a, e) => a.set(e, (a.get(e) || 0) + 1), new Map())Puede obtener answer.keys()las claves y answer.values()los valores como matrices. [...answer]le dará una gran matriz con todas las claves / valores como matrices 2d.
Josh de Qaribou
4

Solución ES6 con reducción (fija):

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

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

Thomas Gotwig
fuente
No estoy seguro de cómo un número representa los recuentos de cada elemento de matriz distinto, como la pregunta formulada.
Ry-
4

Editar 2020 : esta es una respuesta bastante antigua (nueve años). Extender al nativo prototypesiempre generará discusión . Aunque creo que el programador es libre de elegir su propio estilo de programación, aquí hay un enfoque (más moderno) del problema sin extenderlo 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; }

La vieja respuesta (2011): podría extender Array.prototype, así:

KooiInc
fuente
2

Mi solución con 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)

Enlace a REPL.

Michal
fuente
2

Solución usando un mapa con O (n) complejidad de tiempo.

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

Demostración: http://jsfiddle.net/simevidas/bnACW/

Sardorjon Vakkosov
fuente
Mi voto a favor para ti, esto funciona como mantequilla con O (n) complejidad de tiempo
Vishal Shetty
1

Hay una manera mucho mejor y más fácil de hacerlo ramda.js. Código de muestra aquí

const ary = [5, 5, 5, 2, 2, 2, 2, 2, 9, 4]; R.countBy(r=> r)(ary) countBy la documentación está en la documentación

Eshwar Prasad Yaddanapudi
fuente
1

Usando MAP puede tener 2 matrices en la salida: una que contiene las ocurrencias y la otra que contiene el número de ocurrencias.

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
fuente
0

Mira el código a continuación.

<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
fuente
0

Prueba esto:

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
fuente
0

Estaba resolviendo un problema similar en codewars e ideé la siguiente solución que funcionó para mí.

Esto proporciona el recuento más alto de un entero en una matriz y también el entero mismo. Creo que también se puede aplicar a la matriz de cadenas.

Para ordenar correctamente las cuerdas, retire el function(a, b){return a-b}interior de la sort()porción

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
fuente
0

Aquí hay una manera de contar las ocurrencias dentro de una matriz de objetos. También coloca el contenido de la primera matriz dentro de una nueva matriz para ordenar los valores de modo que el orden en la matriz original no se interrumpa. Luego, se utiliza una función recursiva para recorrer cada elemento y contar la propiedad de cantidad de cada objeto dentro de la 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
fuente
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
fuente
Extremadamente derrochador copiar el objeto cada vez. Crea un peor caso cuadrático cuando podría ser lineal.
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
fuente
0

Esta pregunta tiene más de 8 años y muchas, muchas respuestas no tienen realmente en cuenta ES6 y sus numerosas ventajas.

Quizás sea aún más importante pensar en las consecuencias de nuestro código para la recolección de basura / gestión de memoria cada vez que creamos matrices adicionales, hacemos copias dobles o triples de matrices o incluso convertimos matrices en objetos. Estas son observaciones triviales para pequeñas aplicaciones, pero si la escala es un objetivo a largo plazo, piense detenidamente en esto.

Si solo necesita un "contador" para tipos de datos específicos y el punto de partida es una matriz (por lo tanto, supongo que desea una lista ordenada y aprovechar las muchas propiedades y métodos que ofrecen las matrices), puede simplemente iterar a través de matriz1 y completar array2 con los valores y el número de ocurrencias para estos valores encontrados en array1.

Tan sencillo como eso.

Ejemplo de clase simple SimpleCounter (ES6) para programación orientada a objetos y diseño 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
fuente
Pegar una función en una clase sin ninguna razón no la hace orientada a objetos, finalListno tiene ninguna razón para ser una matriz, y esto no tiene ventajas sobre hacerlo correctamente.
Ry-
-1

Aquí hay un método clásico de la vieja escuela para contar matrices.

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

Puede ordenarlo primero si desea un resultado alfabético, pero si desea preservar el orden en que se ingresaron los datos, inténtelo. Los bucles anidados pueden ser un poco más lentos que algunos de los otros métodos en esta página.

MangoPapa7
fuente