Estoy buscando una forma elegante de determinar qué elemento tiene la mayor incidencia ( modo ) en una matriz de JavaScript.
Por ejemplo, en
['pear', 'apple', 'orange', 'apple']
el 'apple'
elemento es el más frecuente.
javascript
mode
tornillo
fuente
fuente
Respuestas:
Este es solo 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; }
fuente
Ha habido algunos desarrollos en javascript desde 2009; pensé en agregar otra opción. Me preocupa menos la eficiencia hasta que en realidad es un problema, por lo que mi definición de código "elegante" (según lo estipulado por el OP) favorece la legibilidad, que por supuesto es subjetiva ...
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 ocurrencias 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.slice
llamada de antemano.Editar: actualicé el ejemplo con algunas flechas gordas de ES6 porque sucedió 2015 y creo que se ven bonitas ... Si le preocupa la compatibilidad con versiones anteriores, puede encontrar esto en el historial de revisiones .
fuente
Según la
George Jempty's
solicitud para que el algoritmo tenga en cuenta los vínculos, propongo una versión modificada delMatthew Flaschen's
algoritmo.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 devolverá ahora una cadena con los elementos de modo delimitados por un
&
símbolo. Cuando se recibe el resultado, se puede dividir en ese&
elemento y tiene su (s) modo (s).Otra opción sería devolver una matriz de elemento (s) 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ía manejar el resultado de la función como una matriz de modos.
fuente
modes
a[array[0]]
como valor inicial. Esto asegurará que tengas duplicados en formatomodes
. Esto debería funcionarvar modes = []
==
to===
para hacer cumplir la igualdad estrictaBasado en la respuesta ES6 + de Emissary , podría usar
Array.prototype.reduce
para hacer su comparación (en lugar de ordenar, hacer estallar y potencialmente mutar su matriz), que creo que parece bastante hábil.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, que no siempre le dará una respuesta veraz si nulo es una opción posible por la que está filtrando, tal vez ese podría ser un segundo argumento opcional
La desventaja, al igual que con otras soluciones, es que no maneja los 'estados de dibujo', pero esto aún podría lograrse con una función de reducción un poco más complicada.
fuente
a=['pear', 'apple', 'orange', 'apple']; b={}; max='', maxi=0; for(let k of a) { if(b[k]) b[k]++; else b[k]=1; if(maxi < b[k]) { max=k; maxi=b[k] } }
fuente
Como estoy usando esta función como un cuestionario para los entrevistadores, publico mi solución:
const highest = arr => (arr || []).reduce( ( acc, el ) => { acc.k[el] = acc.k[el] ? acc.k[el] + 1 : 1 acc.max = acc.max ? acc.max < acc.k[el] ? el : acc.max : el return acc }, { k:{} }).max const test = [0,1,2,3,4,2,3,1,0,3,2,2,2,3,3,2] console.log(highest(test))
fuente
Probando un enfoque declarativo aquí. Esta solución crea un objeto para contar las ocurrencias de cada palabra. Luego filtra el objeto a una matriz comparando el total de apariciones de cada palabra con el valor más alto encontrado en el objeto.
const arr = ['hello', 'world', 'hello', 'again']; const tally = (acc, x) => { if (! acc[x]) { acc[x] = 1; return acc; } acc[x] += 1; return acc; }; const totals = arr.reduce(tally, {}); const keys = Object.keys(totals); const values = keys.map(x => totals[x]); const results = keys.filter(x => totals[x] === Math.max(...values));
fuente
Es hora de otra solución:
function getMaxOccurrence(arr) { var o = {}, maxCount = 0, maxValue, m; for (var i=0, iLen=arr.length; i<iLen; i++) { m = arr[i]; if (!o.hasOwnProperty(m)) { o[m] = 0; } ++o[m]; if (o[m] > maxCount) { maxCount = o[m]; maxValue = m; } } return maxValue; }
Si la brevedad importa (no es así), entonces:
function getMaxOccurrence(a) { var o = {}, mC = 0, mV, m; for (var i=0, iL=a.length; i<iL; i++) { m = a[i]; o.hasOwnProperty(m)? ++o[m] : o[m] = 1; if (o[m] > mC) mC = o[m], mV = m; } return mV; }
Si se deben evitar miembros inexistentes (por ejemplo, matriz dispersa), se requiere una prueba adicional de hasOwnProperty :
function getMaxOccurrence(a) { var o = {}, mC = 0, mV, m; for (var i=0, iL=a.length; i<iL; i++) { if (a.hasOwnProperty(i)) { m = a[i]; o.hasOwnProperty(m)? ++o[m] : o[m] = 1; if (o[m] > mC) mC = o[m], mV = m; } } return mV; } getMaxOccurrence([,,,,,1,1]); // 1
Otras respuestas aquí aparecerán indefinidas .
fuente
Otra solución JS de: https://www.w3resource.com/javascript-exercises/javascript-array-exercise-8.php
Puede probar esto también:
let arr =['pear', 'apple', 'orange', 'apple']; function findMostFrequent(arr) { let mf = 1; let m = 0; let item; for (let i = 0; i < arr.length; i++) { for (let j = i; j < arr.length; j++) { if (arr[i] == arr[j]) { m++; if (m > mf) { mf = m; item = arr[i]; } } } m = 0; } return item; } findMostFrequent(arr); // apple
fuente
Aquí hay otra forma de ES6 de hacerlo con complejidad O (n)
const result = Object.entries( ['pear', 'apple', 'orange', 'apple'].reduce((previous, current) => { if (previous[current] === undefined) previous[current] = 1; else previous[current]++; return previous; }, {})).reduce((previous, current) => (current[1] >= previous[1] ? current : previous))[0]; console.log("Max value : " + result);
fuente
function mode(arr){ return arr.reduce(function(counts,key){ var curCount = (counts[key+''] || 0) + 1; counts[key+''] = curCount; if (curCount > counts.max) { counts.max = curCount; counts.mode = key; } return counts; }, {max:0, mode: null}).mode }
fuente
Aquí está mi solución a este problema, pero con números y usando la nueva función 'Establecer'. No es muy eficaz, pero definitivamente me divertí mucho escribiendo esto y admite múltiples valores máximos.
const mode = (arr) => [...new Set(arr)] .map((value) => [value, arr.filter((v) => v === value).length]) .sort((a,b) => a[1]-b[1]) .reverse() .filter((value, i, a) => a.indexOf(value) === i) .filter((v, i, a) => v[1] === a[0][1]) .map((v) => v[0]) mode([1,2,3,3]) // [3] mode([1,1,1,1,2,2,2,2,3,3,3]) // [1,2]
Por cierto, no use esto para producción, esto es solo una ilustración de cómo puede resolverlo solo con las funciones ES6 y Array.
fuente
Aquí está mi solución: -
function frequent(number){ var count = 0; var sortedNumber = number.sort(); var start = number[0], item; for(var i = 0 ; i < sortedNumber.length; i++){ if(start === sortedNumber[i] || sortedNumber[i] === sortedNumber[i+1]){ item = sortedNumber[i] } } return item } console.log( frequent(['pear', 'apple', 'orange', 'apple']))
fuente
En aras de un código realmente fácil de leer y mantenible, comparto esto:
function getMaxOcurrences(arr = []) { let item = arr[0]; let ocurrencesMap = {}; for (let i in arr) { const current = arr[i]; if (ocurrencesMap[current]) ocurrencesMap[current]++; else ocurrencesMap[current] = 1; if (ocurrencesMap[item] < ocurrencesMap[current]) item = current; } return { item: item, ocurrences: ocurrencesMap[item] }; }
Espero que ayude a alguien;)!
fuente
Esta solución puede devolver varios elementos de una matriz en caso de empate. Por ejemplo, una matriz
arr = [ 3, 4, 3, 6, 4, ];
tiene dos valores de modo:
3
y6
.Aqui esta la solucion.
function find_mode(arr) { var max = 0; var maxarr = []; var counter = []; var maxarr = []; arr.forEach(function(){ counter.push(0); }); for(var i = 0;i<arr.length;i++){ for(var j=0;j<arr.length;j++){ if(arr[i]==arr[j])counter[i]++; } } max=this.arrayMax(counter); for(var i = 0;i<arr.length;i++){ if(counter[i]==max)maxarr.push(arr[i]); } var unique = maxarr.filter( this.onlyUnique ); return unique; }; function arrayMax(arr) { var len = arr.length, max = -Infinity; while (len--) { if (arr[len] > max) { max = arr[len]; } } return max; }; function onlyUnique(value, index, self) { return self.indexOf(value) === index; }
fuente
var mode = 0; var c = 0; var num = new Array(); var value = 0; var greatest = 0; var ct = 0;
Nota: ct es la longitud de la matriz.
function getMode() { for (var i = 0; i < ct; i++) { value = num[i]; if (i != ct) { while (value == num[i + 1]) { c = c + 1; i = i + 1; } } if (c > greatest) { greatest = c; mode = value; } c = 0; } }
fuente
const mode = (str) => { return str .split(' ') .reduce((data, key) => { let counter = data.map[key] + 1 || 1 data.map[key] = counter if (counter > data.counter) { data.counter = counter data.mode = key } return data }, { counter: 0, mode: null, map: {} }) .mode } console.log(mode('the t-rex is the greatest of them all'))
fuente
function mode(array){ var set = Array.from(new Set(array)); var counts = set.map(a=>array.filter(b=>b==a).length); var indices = counts.map((a,b)=>Math.max(...counts)===a?b:0).filter(b=>b!==0); var mode = indices.map(a=>set[a]); return mode; }
fuente
Pruébelo también, esto no tiene en cuenta la versión del navegador.
function mode(arr){ var a = [],b = 0,occurrence; for(var i = 0; i < arr.length;i++){ if(a[arr[i]] != undefined){ a[arr[i]]++; }else{ a[arr[i]] = 1; } } for(var key in a){ if(a[key] > b){ b = a[key]; occurrence = key; } } return occurrence; } alert(mode(['segunda','terça','terca','segunda','terça','segunda']));
fuente
// O(n) var arr = [1, 2, 3, 2, 3, 3, 5, 6]; var duplicates = {}; max = ''; maxi = 0; arr.forEach((el) => { duplicates[el] = duplicates[el] + 1 || 1; if (maxi < duplicates[el]) { max = el; maxi = duplicates[el]; } }); console.log(max);
fuente
Aquí está la versión moderna que usa mapas integrados (por lo que funciona en más cosas que se pueden convertir en cadenas únicas):
'use strict'; const histogram = iterable => { const result = new Map(); for (const x of iterable) { result.set(x, (result.get(x) || 0) + 1); } return result; }; const mostCommon = iterable => { let maxCount = 0; let maxKey; for (const [key, count] of histogram(iterable)) { if (count > maxCount) { maxCount = count; maxKey = key; } } return maxKey; }; console.log(mostCommon(['pear', 'apple', 'orange', 'apple']));
fuente
Supongo que tienes dos enfoques. Ambos tienen ventajas.
Ordene y luego cuente o recorra en bucle y use una tabla hash para hacer el conteo por usted.
La tabla hash es buena porque una vez que haya terminado de procesar, también tendrá todos los elementos distintos. Sin embargo, si tuviera millones de elementos, la tabla hash podría terminar usando mucha memoria si la tasa de duplicación es baja. El método de ordenar y luego contar tendría una huella de memoria mucho más controlable.
fuente
var array = [1, 3, 6, 6, 6, 6, 7, 7, 12, 12, 17], c = {}, // counters s = []; // sortable array for (var i=0; i<array.length; i++) { c[array[i]] = c[array[i]] || 0; // initialize c[array[i]]++; } // count occurrences for (var key in c) { s.push([key, c[key]]) } // build sortable array from counters s.sort(function(a, b) {return b[1]-a[1];}); var firstMode = s[0][0]; console.log(firstMode);
fuente
Puedes probar esto:
// using splice() // get the element with the highest occurence in an array function mc(a) { var us = [], l; // find all the unique elements in the array a.forEach(function (v) { if (us.indexOf(v) === -1) { us.push(v); } }); l = us.length; while (true) { for (var i = 0; i < l; i ++) { if (a.indexOf(us[i]) === -1) { continue; } else if (a.indexOf(us[i]) != -1 && a.length > 1) { // just delete it once at a time a.splice(a.indexOf(us[i]), 1); } else { // default to last one return a[0]; } } } } // using string.match method function su(a) { var s = a.join(), uelms = [], r = {}, l, i, m; a.forEach(function (v) { if (uelms.indexOf(v) === -1) { uelms.push(v); } }); l = uelms.length; // use match to calculate occurance times for (i = 0; i < l; i ++) { r[uelms[i]] = s.match(new RegExp(uelms[i], 'g')).length; } m = uelms[0]; for (var p in r) { if (r[p] > r[m]) { m = p; } else { continue; } } return m; }
fuente
Podrías resolverlo en complejidad O (n)
var arr = [1,3,54,56,6,6,1,6]; var obj = {}; /* first convert the array in to object with unique elements and number of times each element is repeated */ for(var i = 0; i < arr.length; i++) { var x = arr[i]; if(!obj[x]) obj[x] = 1; else obj[x]++; } console.log(obj);//just for reference /* now traverse the object to get the element */ var index = 0; var max = 0; for(var obIndex in obj) { if(obj[obIndex] > max) { max = obj[obIndex]; index = obIndex; } } console.log(index+" got maximum time repeated, with "+ max +" times" );
Simplemente copie y pegue en la consola de Chrome para ejecutar el código anterior.
fuente
Esta función es una función genérica para todo tipo de información. Cuenta la ocurrencia de los elementos y luego devuelve una matriz con el máximo de elementos que ocurren.
function mode () { var arr = [].slice.call(arguments); if ((args.length == 1) && (typeof args[0] === "object")) { args = args[0].mode(); } var obj = {}; for(var i = 0; i < arr.length; i++) { if(obj[arr[i]] === undefined) obj[arr[i]] = 1; else obj[arr[i]]++; } var max = 0; for (w in obj) { if (obj[w] > max) max = obj[w]; } ret_val = []; for (w in obj) { if (obj[w] == max) ret_val.push(w); } return ret_val; }
fuente
function mode(){ var input = $("input").val().split(","); var mode = []; var m = []; var p = []; for(var x = 0;x< input.length;x++){ if(m.indexOf(input[x])==-1){ m[m.length]=input[x]; }} for(var x = 0; x< m.length;x++){ p[x]=0; for(var y = 0; y<input.length;y++){ if(input[y]==m[x]){ p[x]++; }}} for(var x = 0;x< p.length;x++){ if(p[x] ==(Math.max.apply(null, p))){ mode.push(m[x]); }} $("#output").text(mode);}
fuente
Este es mi camino. Intento agrupar datos de puño.
const _ = require("underscore") var test = [ 1, 1, 2, 1 ]; var groupResult = _.groupBy(test, (e)=> e);
El groupResult debe ser
{ 1: [1, 1, 1] 2: [2] }
Luego encuentra la propiedad que tiene la matriz más larga
function findMax(groupResult){ var maxArr = [] var max; for(var item in groupResult){ if(!max) { max = { value:item, count: groupResult[item].length } ; maxArr.push(max); continue; } if(max.count < groupResult[item].length){ maxArr = []; max = { value:item, count: groupResult[item].length } maxArr.push(max) } else if(max === groupResult[item].length) maxArr.push({ value:item, count: groupResult[item].length }) } return maxArr; }
El código completo parece
const _ = require("underscore") var test = [ 1, 1, 2, 1 ]; var groupResult= _.groupBy(test, (e)=> e); console.log(findMax(groupResult)[0].value); function findMax(groupResult){ var maxArr = [] var max; for(var item in groupResult){ if(!max) { max = { value:item, count: groupResult[item].length } ; maxArr.push(max); continue; } if(max.count < groupResult[item].length){ maxArr = []; max = { value:item, count: groupResult[item].length } maxArr.push(max) } else if(max === groupResult[item].length) maxArr.push({ value:item, count: groupResult[item].length }) } return maxArr; }
fuente
var cats = ['Tom','Fluffy','Tom','Bella','Chloe','Tom','Chloe']; var counts = {}; var compare = 0; var mostFrequent; (function(array){ for(var i = 0, len = array.length; i < len; i++){ var word = array[i]; if(counts[word] === undefined){ counts[word] = 1; }else{ counts[word] = counts[word] + 1; } if(counts[word] > compare){ compare = counts[word]; mostFrequent = cats[i]; } } return mostFrequent; })(cats);
fuente
Con ES6, puede encadenar el método de esta manera:
function findMostFrequent(arr) { return arr .reduce((acc, cur, ind, arr) => { if (arr.indexOf(cur) === ind) { return [...acc, [cur, 1]]; } else { acc[acc.indexOf(acc.find(e => e[0] === cur))] = [ cur, acc[acc.indexOf(acc.find(e => e[0] === cur))][1] + 1 ]; return acc; } }, []) .sort((a, b) => b[1] - a[1]) .filter((cur, ind, arr) => cur[1] === arr[0][1]) .map(cur => cur[0]); } console.log(findMostFrequent(['pear', 'apple', 'orange', 'apple'])); console.log(findMostFrequent(['pear', 'apple', 'orange', 'apple', 'pear']));
Si dos elementos tienen la misma ocurrencia, devolverá ambos. Y funciona con cualquier tipo de elemento.
fuente
arr
dentro de un ámbito donde esa variable ya está definida como parámetro. Esto puede provocar errores según el navegador que se utilice.arr
se refierearr.indexOf(cur)
? ¿El parámetro superior, o el que está dentro de reducir?