Obtener el elemento con mayor aparición en una matriz

Resuelto vise asked hace 15 años • 46 respuestas

Estoy buscando una forma elegante de determinar qué elemento tiene la mayor aparición ( modo ) en una matriz de JavaScript.

Por ejemplo, en

['pear', 'apple', 'orange', 'apple']

el 'apple'elemento es el más frecuente.

vise avatar Jun 28 '09 06:06 vise
Aceptado

Este es sólo el modo. Aquí tienes una solución rápida y no optimizada . Debería ser O(n).

function mode(array)
{
    if(array.length == 0)
        return null;
    var modeMap = {};
    var maxEl = array[0], maxCount = 1;
    for(var i = 0; i < array.length; i++)
    {
        var el = array[i];
        if(modeMap[el] == null)
            modeMap[el] = 1;
        else
            modeMap[el]++;  
        if(modeMap[el] > maxCount)
        {
            maxEl = el;
            maxCount = modeMap[el];
        }
    }
    return maxEl;
}
Matthew Flaschen avatar Jun 27 '2009 23:06 Matthew Flaschen

Ha habido algunos avances en JavaScript desde 2009; pensé en agregar otra opción. Me preocupa menos la eficiencia hasta que realmente es un problema, por lo que mi definición de código "elegante" (según lo estipulado por el OP) favorece la legibilidad, lo cual es, por supuesto, subjetivo...

function mode(arr){
    return arr.sort((a,b) =>
          arr.filter(v => v===a).length
        - arr.filter(v => v===b).length
    ).pop();
}

mode(['pear', 'apple', 'orange', 'apple']); // apple

En este ejemplo particular, si dos o más elementos del conjunto tienen apariciones iguales, se devolverá el que aparece más tarde en la matriz. También vale la pena señalar que modificará su matriz original, lo que puede evitarse si lo desea con una Array.slicellamada previa.


Editar: actualicé el ejemplo con algunas flechas gruesas de ES6 porque sucedió en 2015 y creo que se ven bonitas... Si le preocupa la compatibilidad con versiones anteriores, puede encontrar esto en el historial de revisiones .

Emissary avatar Dec 24 '2013 14:12 Emissary

Según la George Jempty'ssolicitud de que el algoritmo tenga en cuenta los vínculos, propongo una versión modificada del Matthew Flaschen'salgoritmo.

function modeString(array) {
  if (array.length == 0) return null;

  var modeMap = {},
    maxEl = array[0],
    maxCount = 1;

  for (var i = 0; i < array.length; i++) {
    var el = array[i];

    if (modeMap[el] == null) modeMap[el] = 1;
    else modeMap[el]++;

    if (modeMap[el] > maxCount) {
      maxEl = el;
      maxCount = modeMap[el];
    } else if (modeMap[el] == maxCount) {
      maxEl += "&" + el;
      maxCount = modeMap[el];
    }
  }
  return maxEl;
}

Esto ahora devolverá una cadena con los elementos de modo delimitados por un &símbolo. Cuando se recibe el resultado, se puede dividir en ese &elemento y tendrá sus modos.

Otra opción sería devolver una matriz de elementos de modo así:

function modeArray(array) {
  if (array.length == 0) return null;
  var modeMap = {},
    maxCount = 1,
    modes = [];

  for (var i = 0; i < array.length; i++) {
    var el = array[i];

    if (modeMap[el] == null) modeMap[el] = 1;
    else modeMap[el]++;

    if (modeMap[el] > maxCount) {
      modes = [el];
      maxCount = modeMap[el];
    } else if (modeMap[el] == maxCount) {
      modes.push(el);
      maxCount = modeMap[el];
    }
  }
  return modes;
}

En el ejemplo anterior, podrá manejar el resultado de la función como una matriz de modos.

samandmoore avatar Aug 10 '2010 17:08 samandmoore

Según la respuesta ES6+ de Emissary , podría utilizarla Array.prototype.reducepara hacer su comparación (en lugar de ordenar, extraer y potencialmente mutar su matriz), lo cual creo que parece bastante ingenioso.

const mode = (myArray) =>
  myArray.reduce(
    (a,b,i,arr)=>
     (arr.filter(v=>v===a).length>=arr.filter(v=>v===b).length?a:b),
    null)

El valor predeterminado es nulo, lo que no siempre le dará una respuesta veraz si nulo es una posible opción por la que está filtrando, tal vez ese podría ser un segundo argumento opcional.

La desventaja, como ocurre con otras soluciones, es que no maneja "estados de extracción", pero esto aún podría lograrse con una función de reducción un poco más complicada.

davidsharp avatar Feb 08 '2017 12:02 davidsharp