Encuentra el elemento min / max de una matriz en JavaScript


779

¿Cómo puedo obtener fácilmente el elemento min o max de una matriz de JavaScript?

Psuedocódigo de ejemplo:

let array = [100, 0, 50]

array.min() //=> 0
array.max() //=> 100

93
Nota: Con ECMAScript 6 puede utilizar el nuevo operador de difusión (tres puntos: ...) con Math.max()la siguiente manera: Math.max(...[2, 5, 16, 1]). Vea mi respuesta hecha de la documentación de MDN .
totymedli

1
Considere marcar una respuesta como aceptada.
Alex

aquí un punto de referencia para una comparación de la velocidad de las formas más comunes de hacerlo: jsben.ch/#/1QuTg
EscapeNetscape

es6 es básicamente excelente! :)
datdinhquoc

Sin ES6 Math.max.apply(null, [2,5,16,1])
Tomer

Respuestas:


828

¿Qué tal aumentar el objeto Array incorporado para usar Math.max/ en su Math.minlugar:

Array.prototype.max = function() {
  return Math.max.apply(null, this);
};

Array.prototype.min = function() {
  return Math.min.apply(null, this);
};

Aquí hay un JSFiddle .

Aumentar los muebles empotrados puede causar colisiones con otras bibliotecas (algunos ven), por lo que puede ser más cómodo con sólo apply'ing Math.xxx()a la matriz directamente:

var min = Math.min.apply(null, arr),
    max = Math.max.apply(null, arr);

Alternativamente, suponiendo que su navegador sea compatible con ECMAScript 6, puede usar el operador de propagación que funciona de manera similar al applymétodo:

var min = Math.min( ...arr ),
    max = Math.max( ...arr );

8
@HankH: pasar nullo Matho {}lo que sea apply()o call()no tiene relación con el resultado. Math.maxno hace ni debe hacer referencia thisinternamente.
Roatin Marth el

31
Como programador de C #, necesito preguntas muy tipadas.
ChaosPandion el

77
Solo compartí un error de jQuery que estaba cometiendo con el código anterior, lo que me llevó mucho tiempo depurar. Una matriz jquery funciona bien en todo menos en el iPad. Tuve que convertir la matriz en una verdadera matriz nativa para que funcione. Solo afectó al dispositivo único por alguna razónMath.max.apply(null, $.makeArray(array));
Forrest

11
He votado en contra, porque el enfoque propuesto consume memoria O (n) en el marco de la pila y, como resultado, se bloquea en matrices grandes. En mi caso, solo unos 130000 números fueron suficientes para bloquear nodejs.
Alexey Timanovsky

14
No aumente los prototipos incorporados como este. No se trata solo de conflictos con otras bibliotecas; También se trata del potencial de que el navegador mismo proporcione un método .maxo un .minmétodo en el futuro. Escenario perfectamente realista: utiliza esta respuesta. En 2016, las especificaciones ES7 o ES8 Array.maxy Array.min. A diferencia de esta versión, trabajan en cadenas. Su futuro colega intenta obtener la secuencia alfabéticamente más reciente en una matriz con el .max()método nativo ahora bien documentado , pero lo consigue misteriosamente NaN. Horas después, encuentra este código, ejecuta un git blamey maldice su nombre.
Mark Amery

362
var max_of_array = Math.max.apply(Math, array);

Para una discusión completa ver: http://aaroncrane.co.uk/2008/11/javascript_max_api/


13
¿Cuál es la diferencia entre Math.max.apply(Math, array)y Math.max.apply(null, array)? El blog dice "... también tienes que repetir de forma redundante que maxpertenece a Math...", pero parece que no tengo que hacerlo (estableciendo el primer argumento de applyas null).
ziyuang

99
@ziyuang Cuando lo llamas como Math.max(a,b), Mathse pasa como el thisvalor, por lo que puede tener sentido hacer lo mismo al llamar con apply. Pero Math.maxno utiliza el thisvalor, por lo que puede pasar el valor que desee.
Oriol

199

Para grandes matrices (~ 10⁷ elementos), Math.miny Math.maxambas producen el siguiente error en Node.js.

RangeError: se excedió el tamaño máximo de la pila de llamadas

Una solución más robusta es no agregar todos los elementos a la pila de llamadas, sino pasar una matriz:

function arrayMin(arr) {
  return arr.reduce(function (p, v) {
    return ( p < v ? p : v );
  });
}

function arrayMax(arr) {
  return arr.reduce(function (p, v) {
    return ( p > v ? p : v );
  });
}

Si le preocupa la velocidad, el siguiente código es ~ 3 veces más rápido Math.max.applyque en mi computadora. Ver http://jsperf.com/min-and-max-in-array/2 .

function arrayMin(arr) {
  var len = arr.length, min = Infinity;
  while (len--) {
    if (arr[len] < min) {
      min = arr[len];
    }
  }
  return min;
};

function arrayMax(arr) {
  var len = arr.length, max = -Infinity;
  while (len--) {
    if (arr[len] > max) {
      max = arr[len];
    }
  }
  return max;
};

Si sus matrices contienen cadenas en lugar de números, también debe convertirlas en números. El siguiente código hace eso, pero ralentiza el código ~ 10 veces en mi máquina. Ver http://jsperf.com/min-and-max-in-array/3 .

function arrayMin(arr) {
  var len = arr.length, min = Infinity;
  while (len--) {
    if (Number(arr[len]) < min) {
      min = Number(arr[len]);
    }
  }
  return min;
};

function arrayMax(arr) {
  var len = arr.length, max = -Infinity;
  while (len--) {
    if (Number(arr[len]) > max) {
      max = Number(arr[len]);
    }
  }
  return max;
};

asignar miny maxal último elemento y reducir las iteraciones en 1 ( while(--len));)
Venugopal

@Venugopal, entonces necesita una verificación especial para ver si la matriz está vacía y devolver +/- Infinito
Linus Unnebäck

2
Extraño ... Fui al sitio web vinculado ... y probando en Firefox 51.0.0 / Mac OS X 10.12.0, el enfoque basado en la reducción es un 30% más lento que el basado en el bucle ... resultados muy diferentes
Pierpaolo Cira

2
very different results lo hiciste 5 años después)
Алексей Лещук

1
En 2019 la reducesolución es la más lenta. Incluso si trabaja con una matriz que tiene millones de elementos, es mejor usar el estándar for loop . Vea mi respuesta para más.
totymedli

152

Uso del operador de propagación (ES6)

Math.max(...array);  // the same with "min" => Math.min(...array);


8
Esta solución ya fue proporcionada por muchas otras respuestas.
totymedli

15
Math.max (... []) = -Infinito. jajaja
David

@DavidPortabella no estoy segura de por qué es gracioso. Así es como funciona según las especificaciones :If no arguments are given, the result is -∞.
Patrick Roberts

3
Sí, quise decir que la especificación de JavaScript es horrible. Parece obvio que el mínimo de ningún número no se puede calcular. En otros lenguajes de programación más serios, como Scala, pedir el mínimo de una matriz vacía arroja una excepción.
David Portabella

3
Scala es para personas que necesitan una máquina para decirles que lo hicieron mal
thedanotto

107

tl; dr

// For regular arrays:
var max = Math.max(...arrayOfNumbers);

// For arrays with tens of thousands of items:
let max = testArray[0];
for (let i = 1; i < testArrayLength; ++i) {
  if (testArray[i] > max) {
    max = testArray[i];
  }
}

Solución MDN

Los documentos oficiales de MDNMath.max() ya cubren este tema:

La siguiente función usa Function.prototype.apply () para encontrar el elemento máximo en una matriz numérica. getMaxOfArray([1, 2, 3])es equivalente a Math.max(1, 2, 3), pero puedes usargetMaxOfArray() en matrices construidas mediante programación de cualquier tamaño.

function getMaxOfArray(numArray) {
    return Math.max.apply(null, numArray);
}

O con el nuevo operador de propagación , obtener el máximo de una matriz se vuelve mucho más fácil.

var arr = [1, 2, 3];
var max = Math.max(...arr);

Tamaño máximo de una matriz

De acuerdo con MDN, las applysoluciones extendidas tenían una limitación de 65536 que provenía del límite del número máximo de argumentos:

Pero tenga cuidado: al usar Apply de esta manera, corre el riesgo de exceder el límite de longitud del argumento del motor JavaScript. Las consecuencias de aplicar una función con demasiados argumentos (piense más de decenas de miles de argumentos) varían entre motores ( JavaScriptCore tiene un límite de argumento codificado de 65536 ), porque el límite (incluso la naturaleza de cualquier pila excesivamente grande comportamiento) no está especificado. Algunos motores arrojarán una excepción. Más perniciosamente, otros limitarán arbitrariamente el número de argumentos realmente pasados ​​a la función aplicada. Para ilustrar este último caso: si dicho motor tuviera un límite de cuatro argumentos (los límites reales son, por supuesto, significativamente más altos), sería como si los argumentos 5, 6, 2, 3 se hubieran pasado para aplicar en los ejemplos anteriores, en lugar de la matriz completa.

Incluso proporcionan una solución híbrida que realmente no tiene un buen rendimiento en comparación con otras soluciones. Consulte la prueba de rendimiento a continuación para obtener más información.

En 2019, el límite real es el tamaño máximo de la pila de llamadas . Para los navegadores de escritorio modernos basados ​​en Chromium, esto significa que cuando se trata de encontrar min / max con applyo spread, prácticamente el tamaño máximo para matrices de números solamente es ~ 120000 . Por encima de esto, habrá un desbordamiento de pila y se lanzará el siguiente error:

RangeError: se excedió el tamaño máximo de la pila de llamadas

Con el siguiente script (basado en esta publicación de blog ), al detectar ese error puede calcular el límite para su entorno específico.

¡Advertencia! ¡Ejecutar este script lleva tiempo y, dependiendo del rendimiento de su sistema, puede ralentizar o bloquear su navegador / sistema!

let testArray = Array.from({length: 10000}, () => Math.floor(Math.random() * 2000000));
for (i = 10000; i < 1000000; ++i) {
  testArray.push(Math.floor(Math.random() * 2000000));
  try {
    Math.max.apply(null, testArray);
  } catch (e) {
    console.log(i);
    break;
  }
}

Rendimiento en matrices grandes

Basado en la prueba en el comentario de EscapeNetscape , creé algunos puntos de referencia que prueban 5 métodos diferentes en una matriz de solo números aleatorios con 100000 elementos .

En 2019, los resultados muestran que el bucle estándar (que por cierto no tiene la limitación de tamaño) es el más rápido en todas partes. applyy la propagación viene de cerca, luego mucho más tarde la solución híbrida de MDN y luego reducecomo la más lenta.

Casi todas las pruebas dieron los mismos resultados, excepto una en la que la propagación resultó ser la más lenta.

Si intensifica su matriz para tener 1 millón de elementos, las cosas comienzan a romperse y queda con el bucle estándar como una solución rápida y reducemás lenta.

Punto de referencia JSPerf

Resultados de referencia de jsperf.com para diferentes soluciones para encontrar el elemento mínimo / máximo de una matriz

Punto de referencia JSBen

Resultados de referencia de jsben.com para diferentes soluciones para encontrar el elemento mínimo / máximo de una matriz

Punto de referencia JSBench.me

Resultados de referencia de jsbench.me para diferentes soluciones para encontrar el elemento min / max de una matriz

Código fuente de referencia


Si está utilizando el mecanografiado, el operador de propagación como se muestra se compila Math.max.apply(Math, arr)para una compatibilidad 'máxima'.
Simon_Weaver

1
También de MDN: "ambos se propagan (...)y applyfallarán o devolverán el resultado incorrecto si la matriz tiene demasiados elementos [...] La solución de reducción no tiene este problema" Al probar Chrome, FF, Edge e IE11 parece que es ok para una matriz de hasta 100k valores. (Probado en Win10 y los últimos navegadores: Chrome 110k, Firefox 300k, Edge 400k, IE11 150k).
oriadam el

Este es un método muy lento, ¿y si la matriz tuviera miles de elementos?
Slava Fomin II

@SlavaFominII Extendí la respuesta para que cubra matrices con miles de elementos.
totymedli

68

Si eres paranoico como yo sobre el uso Math.max.apply(lo que podría causar errores cuando se le dan matrices grandes de acuerdo con MDN ), intente esto:

function arrayMax(array) {
  return array.reduce(function(a, b) {
    return Math.max(a, b);
  });
}

function arrayMin(array) {
  return array.reduce(function(a, b) {
    return Math.min(a, b);
  });
}

O, en ES6:

function arrayMax(array) {
  return array.reduce((a, b) => Math.max(a, b));
}

function arrayMin(array) {
  return array.reduce((a, b) => Math.min(a, b));
}

Desafortunadamente, las funciones anónimas son necesarias (en lugar de usar Math.max.bind(Math)porque reduceno solo pasan ay ba su función, sino también iy una referencia a la matriz en sí, por lo que debemos asegurarnos de no tratar de invocarlas maxtambién.


Su ejemplo de ES6, ¿hay alguna razón por la que no solo regrese Math.max(...array)?
Wojciech Bednarski

@WojciechBednarski esta página parece sugerir que usar el operador de propagación es lo mismo que pasarle una matriz y apply, por lo tanto, tiene los mismos inconvenientes (límite máximo de argumentos).
Daniel Buckmaster

Gracias por esto. Solo puede corregir el soporte faltante después de la reducción:function arrayMax(array) { return array.reduce(function(a, b) { return Math.max(a, b); }); // <--------- missing ) }
Arkowsky

1
@DanielDietrich Supongo que hacer el equivalente, llamar Math.min()sin valores, devuelve Infinity, por lo que estas funciones podrían usarse reduce(..., Infinity)para coincidir con ese comportamiento. Sin embargo, prefiero que arroje una excepción (como lo hace actualmente), porque tomar el mínimo de una matriz vacía parece ser un error.
Daniel Buckmaster

1
Hasta ahora reducir es el más lento.
Алексей Лещук

40

.apply a menudo se usa cuando la intención es invocar una función variadic con una lista de valores de argumentos, por ej.

La Math.max([value1[,value2, ...]])función devuelve el mayor de cero o más números.

Math.max(10, 20); // 20
Math.max(-10, -20); // -10
Math.max(-10, 20); // 20

El Math.max()método no le permite pasar en una matriz. Si tiene una lista de valores de los cuales necesita obtener el mayor, normalmente llamaría a esta función usando Function.prototype.apply () , por ejemplo

Math.max.apply(null, [10, 20]); // 20
Math.max.apply(null, [-10, -20]); // -10
Math.max.apply(null, [-10, 20]); // 20

Sin embargo, a partir del ECMAScript 6 puede usar el operador de propagación :

El operador de propagación permite que una expresión se expanda en lugares donde se esperan múltiples argumentos (para llamadas a funciones) o múltiples elementos (para literales de matriz).

Usando el operador de propagación, lo anterior puede reescribirse como tal:

Math.max(...[10, 20]); // 20
Math.max(...[-10, -20]); // -10
Math.max(...[-10, 20]); // 20

Al llamar a una función utilizando el operador variable, incluso puede agregar valores adicionales, por ejemplo

Math.max(...[10, 20], 50); // 50
Math.max(...[-10, -20], 50); // 50

Prima:

Operador de difusión le permite utilizar la sintaxis literal de matriz para crear nuevas matrices en situaciones donde en la ES5 que tendría que recurrir al código imperativo, utilizando una combinación de push, splice, etc.

let foo = ['b', 'c'];
let bar = ['a', ...foo, 'd', 'e']; // ['a', 'b', 'c', 'd', 'e']

1
La concatmayoría de los programadores escribirán su último ejemplo en la bonificación porque le permite mantener un estilo de línea única.
Cody Allan Taylor

31

Dos formas son más cortas y fáciles:

let arr = [2, 6, 1, 0]

Camino 1 :

let max = Math.max.apply(null, arr)

Camino 2 :

let max = arr.reduce(function(a, b) {
    return Math.max(a, b);
});

Tenga cuidado si la matriz está vacía: obtendrá un infinito negativo que puede no ser lo que desea. Si prefiere obtener 0, puede usar [0].concat(arr)o con sintaxis extendida [0, ...arr](en lugar de 'arr')
Simon_Weaver

¿Hay alguna manera de excluir valores nulos en el Camino 1?
bonbon.langes

22

Lo haces extendiendo el tipo de matriz:

Array.max = function( array ){
    return Math.max.apply( Math, array );
};
Array.min = function( array ){
    return Math.min.apply( Math, array );
}; 

Impulsado desde aquí (por John Resig)


20

Una solución simple para encontrar el valor mínimo sobre uno Arrayde los elementos es usar la Arrayfunción prototipo reduce:

A = [4,3,-9,-2,2,1];
A.reduce((min, val) => val < min ? val : min, A[0]); // returns -9

o usando la función incorporada Math.Min () de JavaScript (gracias @Tenflex):

A.reduce((min,val) => Math.min(min,val), A[0]);

Esto se establece minen A[0], y luego verifica A[1]...A[n]si es estrictamente menor que el actual min. Si A[i] < minluego minse actualiza a A[i]. Cuando se han procesado todos los elementos de la matriz, minse devuelve como resultado.

EDITAR : Incluir posición de valor mínimo:

A = [4,3,-9,-2,2,1];
A.reduce((min, val) => val < min._min ? {_min: val, _idx: min._curr, _curr: min._curr + 1} : {_min: min._min, _idx: min._idx, _curr: min._curr + 1}, {_min: A[0], _idx: 0, _curr: 0}); // returns { _min: -9, _idx: 2, _curr: 6 }

3
A.reduce ((min, val) => Math.min (min, val), A [0]); aún más corto
Tenflex

Como pregunta adicional, ¿cómo tener no solo un minvalor devuelto sino también su posición en la matriz?
stevek

@meshfields - He actualizado la respuesta.
Nicolas Lykke Iversen

15

Otros ya han dado algunas soluciones en las que aumentan Array.prototype. Todo lo que quiero en esta respuesta es aclarar si debería ser Math.min.apply( Math, array )o Math.min.apply( null, array ). Entonces, ¿qué contexto se debe utilizar Matho null?

Al pasar nullcomo contexto a apply, el contexto se convertirá por defecto en el objeto global (el windowobjeto en el caso de los navegadores). Pasar el Mathobjeto como contexto sería la solución correcta, pero tampoco le hará daño pasar null. Aquí hay un ejemplo de cuándo nullpodría causar problemas al decorar la Math.maxfunción:

// decorate Math.max
(function (oldMax) {
    Math.max = function () {
        this.foo(); // call Math.foo, or at least that's what we want

        return oldMax.apply(this, arguments);
    };
})(Math.max);

Math.foo = function () {
    print("foo");
};

Array.prototype.max = function() {
  return Math.max.apply(null, this); // <-- passing null as the context
};

var max = [1, 2, 3].max();

print(max);

Lo anterior arrojará una excepción porque this.foose evaluará como window.foo, que es undefined. Si reemplazamos nullcon Math, las cosas funcionarán como se esperaba y la cadena "foo" se imprimirá en la pantalla (probé esto usando Mozilla Rhino ).

Se puede suponer que nadie lo ha decorado Math.max, así que pasar nullfuncionará sin problemas.


2
Punto a favor. Sin embargo, ¿por qué alguien decoraría Foo.staticMethody haría referencia this? ¿No sería eso un error en el diseño del decorador? (a menos que, por supuesto, quisieran hacer referencia al alcance global y quieran permanecer independientes del motor de JavaScript que se utiliza, por ejemplo, Rhino).
Roatin Marth el

1
La especificación es explícita sobre qué funciones especificadas deberían referirse al " valor de este " (de hecho, esa frase aparece 125 veces en la especificación). Math.max, implementado por especificación, no utiliza this. Si alguien anula de Math.maxtal manera que sí lo usa this, entonces ha hecho que su comportamiento viole las especificaciones y usted debe arrojarles objetos afilados. No debe codificar alrededor de esa posibilidad más de lo que codificaría alrededor de la posibilidad de que alguien haya cambiado Math.maxy Math.minpor el lulz.
Mark Amery

15

Una forma más de hacerlo:

var arrayMax = Function.prototype.apply.bind(Math.max, null);

Uso:

var max = arrayMax([2, 5, 1]);

¿Alguien puede explicar cómo funciona esto? Esto es bastante tonto. ¿Es correcto mi entendimiento: arrayMax es una función y vinculamos algo a una propiedad de su prototipo? ¿Qué es esto apply.bind y cada prototipo lo tiene?
Sam


14

Metodos alternativos


Los métodos Math.miny Math.maxson operaciones recursivas que se agregan a la pila de llamadas del motor JS, y muy probablemente se bloquean para una matriz que contiene una gran cantidad de elementos
(más de ~ 10⁷ elementos, depende del navegador del usuario).

Math.max (... Array (1000000) .keys ());

RangeError no capturado: se excedió el tamaño máximo de la pila de llamadas

En cambio, use algo como esto:

arr.reduce((max, val) => max > val ? max : val, arr[0])

O con mejor tiempo de ejecución:

function maxValue(arr) {
  let max = arr[0];

  for (let val of arr) {
    if (val > max) {
      max = val;
    }
  }
  return max;
}

O para obtener Min y Max:

function getMinMax(arr) {
  return arr.reduce(({min, max}, v) => ({
    min: min < v ? min : v,
    max: max > v ? max : v,
  }), { min: arr[0], max: arr[0] });
}

O con un tiempo de ejecución aún mejor *:

function getMinMax(arr) {
  let min = arr[0];
  let max = arr[0];
  let i = arr.length;

  while (i--) {
    min = arr[i] < min ? arr[i] : min;
    max = arr[i] > max ? arr[i] : max;
  }
  return { min, max };
}

* Probado con 1,000,000 de elementos:
solo como referencia, el tiempo de ejecución de la primera función (en mi máquina) fue de 15.84 ms frente a la segunda función con solo 4.32 ms.


13

Esto puede adaptarse a sus propósitos.

Array.prototype.min = function(comparer) {

    if (this.length === 0) return null;
    if (this.length === 1) return this[0];

    comparer = (comparer || Math.min);

    var v = this[0];
    for (var i = 1; i < this.length; i++) {
        v = comparer(this[i], v);    
    }

    return v;
}

Array.prototype.max = function(comparer) {

    if (this.length === 0) return null;
    if (this.length === 1) return this[0];

    comparer = (comparer || Math.max);

    var v = this[0];
    for (var i = 1; i < this.length; i++) {
        v = comparer(this[i], v);    
    }

    return v;
}

debe inicializar su v con 'this [0]' en caso de que ningún número sea menor que 0
jasonmw 03 de

¿Se comparersupone que debe llamarse en algún ámbito específico? Porque como se hace referencia this[index]que es undefinedcada vez.
Roatin Marth el

Solucionado, siempre me olvido del alcance del nivel de función.
ChaosPandion el

Oh, ahora, ahora @Ionut G. Stan le critique por el mismo argumento "contexto equivocado", como él me hizo, ya que su comparador predeterminado ( Math.xxx) se ejecuta en el ámbito global ...
Roatin Marth

Eso puede ser cierto, pero la firma de la nueva función no requiere alcance ya que toma los 2 objetos que deben compararse.
ChaosPandion el



9

Para grandes matrices (~ 10⁷ elementos), Math.minyMath.max obtiene un RangeError (Tamaño máximo de la pila de llamadas excedido) en node.js.

Para matrices grandes, una solución rápida y sucia es:

Array.prototype.min = function() {
    var r = this[0];
    this.forEach(function(v,i,a){if (v<r) r=v;});
    return r;
};

8

Tuve el mismo problema, necesitaba obtener los valores mínimos y máximos de una matriz y, para mi sorpresa, no había funciones integradas para las matrices. Después de leer mucho, decidí probar yo mismo las "3 mejores soluciones":

  1. solución discreta: un bucle FOR para verificar cada elemento de la matriz con el valor máximo y / o mínimo actual;
  2. SOLUCIÓN APLICAR: enviar la matriz a las funciones internas de Math.max y / o Math.min usando apply (null, array);
  3. Solución REDUCIR: recurrir a una comprobación de cada elemento de la matriz utilizando reduce (función).

El código de prueba fue este:

function GetMaxDISCRETE(A)
{   var MaxX=A[0];

    for (var X=0;X<A.length;X++)
        if (MaxX<A[X])
            MaxX=A[X];

    return MaxX;
}

function GetMaxAPPLY(A)
{   return Math.max.apply(null,A);
}

function GetMaxREDUCE(A)
{   return A.reduce(function(p,c)
    {   return p>c?p:c;
    });
}

La matriz A se llenó con 100,000 números enteros aleatorios, cada función se ejecutó 10,000 veces en Mozilla Firefox 28.0 en un escritorio Intel Pentium 4 a 2.99GHz con Windows Vista. Los tiempos están en segundos, recuperados por la función performance.now (). Los resultados fueron estos, con 3 dígitos fraccionarios y desviación estándar:

  1. Solución discreta: media = 0.161s, sd = 0.078
  2. APLICAR solución: media = 3.571s, sd = 0.487
  3. REDUCIR la solución: media = 0.350s, sd = 0.044

La solución REDUCE fue un 117% más lenta que la solución discreta. La solución APLICAR fue la peor, 2,118% más lenta que la solución discreta. Además, como observó Peter, no funciona para matrices grandes (más de 1,000,000 de elementos).

Además, para completar las pruebas, probé este código discreto extendido:

var MaxX=A[0],MinX=A[0];

for (var X=0;X<A.length;X++)
{   if (MaxX<A[X])
        MaxX=A[X];
    if (MinX>A[X])
        MinX=A[X];
}

El tiempo: media = 0.218s, sd = 0.094

Por lo tanto, es un 35% más lento que la solución discreta simple, pero recupera los valores máximos y mínimos al mismo tiempo (cualquier otra solución tomaría al menos el doble para recuperarlos). Una vez que el OP necesitara ambos valores, la solución discreta sería la mejor opción (incluso si dos funciones separadas, una para calcular el máximo y otra para calcular el mínimo, superarían a la segunda mejor, la solución REDUCIR).


8

Puede usar la siguiente función en cualquier parte de su proyecto:

function getMin(array){
    return Math.min.apply(Math,array);
}

function getMax(array){
    return Math.max.apply(Math,array);
}

Y luego puede llamar a las funciones que pasan la matriz:

var myArray = [1,2,3,4,5,6,7];
var maximo = getMax(myArray); //return the highest number

8

El siguiente código funciona para mí:

var valueList = [10,4,17,9,3];
var maxValue = valueList.reduce(function(a, b) { return Math.max(a, b); });
var minValue = valueList.reduce(function(a, b) { return Math.min(a, b); });

7

Iterar a través, manteniendo un registro sobre la marcha.

var min = null;
var max = null;
for (var i = 0, len = arr.length; i < len; ++i)
{
    var elem = arr[i];
    if (min === null || min > elem) min = elem;
    if (max === null || max < elem) max = elem;
}
alert( "min = " + min + ", max = " + max );

Esto dejará min / max nulo si no hay elementos en la matriz. Establecerá min y max en una pasada si la matriz tiene algún elemento.

También puede extender Array con un rangemétodo que utiliza lo anterior para permitir la reutilización y mejorar la legibilidad. Vea un violín de trabajo en http://jsfiddle.net/9C9fU/

Array.prototype.range = function() {

    var min = null,
        max = null,
        i, len;

    for (i = 0, len = this.length; i < len; ++i)
    {
        var elem = this[i];
        if (min === null || min > elem) min = elem;
        if (max === null || max < elem) max = elem;
    }

    return { min: min, max: max }
};

Usado como

var arr = [3, 9, 22, -7, 44, 18, 7, 9, 15];

var range = arr.range();

console.log(range.min);
console.log(range.max);

@JordanDillonChapian Estoy de acuerdo, pero sería trivial extender esto a una rangefunción que sería la mejor manera de obtener el mínimo y el máximo al mismo tiempo IMO, como lo hice con una actualización de mi respuesta.
tvanfosson

6

Pensé en compartir mi solución simple y fácil de entender.

Para el min:

var arr = [3, 4, 12, 1, 0, 5];
var min = arr[0];
for (var k = 1; k < arr.length; k++) {
  if (arr[k] < min) {
    min = arr[k];
  }
}
console.log("Min is: " + min);

Y para el máximo:

var arr = [3, 4, 12, 1, 0, 5];
var max = arr[0];
for (var k = 1; k < arr.length; k++) {
  if (arr[k] > max) {
    max = arr[k];
  }
}
console.log("Max is: " + max);



Gracias. Cambié mi respuesta.
Ionut Necula

La iteración sigue siendo incorrecta (acceso a propiedades no existentes).
Bergi

Lo que está mal, no veo nada malo. ¿Puedes ofrecer un ejemplo por favor?
Ionut Necula

1
Modificado en consecuencia ahora. Espero haberte entendido correctamente.
Ionut Necula

5

Cosas simples, de verdad.

var arr = [10,20,30,40];
arr.max = function() { return  Math.max.apply(Math, this); }; //attach max funct
arr.min = function() { return  Math.min.apply(Math, this); }; //attach min funct

alert("min: " + arr.min() + " max: " + arr.max());

5

Aquí hay una forma de obtener el valor máximo de una matriz de objetos. Cree una copia (con corte), luego ordene la copia en orden descendente y tome el primer elemento.

var myArray = [
    {"ID": 1, "Cost": 200},
    {"ID": 2, "Cost": 1000},
    {"ID": 3, "Cost": 50},
    {"ID": 4, "Cost": 500}
]

maxsort = myArray.slice(0).sort(function(a, b) { return b.ID - a.ID })[0].ID; 

5

Usando Math.max()oMath.min()

Math.max(10, 20);   //  20
Math.min(-10, -20); // -20

La siguiente función se utiliza Function.prototype.apply()para encontrar el elemento máximo en una matriz numérica. getMaxOfArray([1, 2, 3])es equivalente a Math.max(1, 2, 3), pero puede usarlo getMaxOfArray()en matrices construidas mediante programación de cualquier tamaño.

function getMaxOfArray(numArray) {
  return Math.max.apply(null, numArray);
}

O con el nuevo operador de propagación, obtener el máximo de una matriz se vuelve mucho más fácil.

var arr = [1, 2, 3];
var max = Math.max(...arr); // 3
var min = Math.min(...arr); // 1

5

Además de usar la función matemática max y min, otra función a usar es la función incorporada de sort (): aquí vamos

const nums = [12, 67, 58, 30].sort((x, y) => 
x -  y)
let max = nums[0]
let min = nums[nums.length -1]

4

La solución de ChaosPandion funciona si está utilizando un prototipo. Si no, considere esto:

Array.max = function( array ){
    return Math.max.apply( Math, array );
};

Array.min = function( array ){
    return Math.min.apply( Math, array );
};

Lo anterior devolverá NaN si un valor de matriz no es un entero, por lo que debe crear alguna funcionalidad para evitar eso. De lo contrario, esto funcionará.


jeerose, ¿por qué tienes (Math, this) como grupos cuando Roatin Marth solo tiene (null, this)?
HankH el

@HankH: vea mi respuesta a su comentario en un comentario a mi propia respuesta.
Roatin Marth el

1
No entiendo lo que quieres decir con "la solución de ChaosPandion funciona si estás usando un prototipo". ¿Cómo es su solución diferente, excepto que está utilizando el Mathobjeto como contexto?
Ionuț G. Stan

Lo siento, quiero decir que si extiendes el prototipo, el tuyo funcionará. Disculpas
Jay

Entonces, ¿cuál es mejor, jeerose o ChaosPandion's?
HankH el

3

Si usa la biblioteca sugar.js , puede escribir arr.min () y arr.max () como sugiere. También puede obtener valores mínimos y máximos de matrices no numéricas.

min (map, all = false) Devuelve el elemento en la matriz con el valor más bajo. map puede ser una función que asigna el valor a verificar o una cadena que actúa como un atajo. Si todo es verdadero, devolverá todos los valores mínimos en una matriz.

max (map, all = false) Devuelve el elemento en la matriz con el mayor valor. map puede ser una función que asigna el valor a verificar o una cadena que actúa como un atajo. Si todo es verdadero, devolverá todos los valores máximos en una matriz.

Ejemplos:

[1,2,3].min() == 1
['fee','fo','fum'].min('length') == "fo"
['fee','fo','fum'].min('length', true) == ["fo"]
['fee','fo','fum'].min(function(n) { return n.length; }); == "fo"
[{a:3,a:2}].min(function(n) { return n['a']; }) == {"a":2}
['fee','fo','fum'].max('length', true) == ["fee","fum"]

Bibliotecas como Lo-Dash y underscore.js también proporcionan funciones mínimas y máximas potentes similares:

Ejemplo de Lo-Dash:

_.max([4, 2, 8, 6]) == 8
var characters = [
  { 'name': 'barney', 'age': 36 },
  { 'name': 'fred',   'age': 40 }
];
_.max(characters, function(chr) { return chr.age; }) == { 'name': 'fred', 'age': 40 }

3
let arr = [2,5,3,5,6,7,1];

let max = Math.max(...arr); // 7
let min = Math.min(...arr); // 1

2
Esta respuesta ya ha sido proporcionada por muchos otros respondedores a esta pregunta. ¿Qué agrega tu respuesta?
Nick

3

Tratar

let max= a=> a.reduce((m,x)=> m>x ? m:x);
let min= a=> a.reduce((m,x)=> m<x ? m:x);

Para Math.min / max (+ apply) obtenemos el error:

Tamaño de pila de llamadas máximo excedido (Chrome 74.0.3729.131)

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.