Encontre o elemento mínimo/máximo de um array em JavaScript
Como posso obter facilmente o elemento mínimo ou máximo de um array JavaScript?
Exemplo de pseudocódigo:
let array = [100, 0, 50]
array.min() //=> 0
array.max() //=> 100
Resposta #1
Que tal aumentar o objeto Array embutido para usar Math.max/Math.min em vez de:
Array.prototype.max = function() {
return Math.max.apply(null, this);
};
Array.prototype.min = function() {
return Math.min.apply(null, this);
};
let p = [35,2,65,7,8,9,12,121,33,99];
console.log(`Max value is: ${p.max()}` +
`\nMin value is: ${p.min()}`);Aqui está um JSFiddle.
Aumentar os recursos internos pode causar colisões com outras bibliotecas (alguns percebem), então você pode se sentir mais confortável apenas usando apply com Math.xxx() diretamente no seu array:
var min = Math.min.apply(null, arr),
max = Math.max.apply(null, arr);
Alternativamente, assumindo que seu navegador suporta ECMAScript 6, você pode usar a sintaxe spread, que funciona de forma semelhante ao método apply:
var min = Math.min( ...arr ),
max = Math.max( ...arr );
Resposta #2
var max_of_array = Math.max.apply(Math, array);
Para uma discussão completa, veja: http://aaroncrane.co.uk/2008/11/javascript_max_api/
Resposta #3
Usando o operador spread (ES6)
Math.max(...array) // The same with "min" => Math.min(...array)
const array = [10, 2, 33, 4, 5];
console.log(
Math.max(...array)
)Resposta #4
Para grandes arrays (~10⁷ elementos), Math.min e Math.max ambos produzem o seguinte erro no Node.js.
RangeError: Tamanho máximo da pilha de chamadas excedido
Uma solução mais robusta é não adicionar cada elemento à pilha de chamadas, mas sim passar um array:
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 );
});
}
Se você está preocupado com a velocidade, o seguinte código é aproximadamente 3 vezes mais rápido do que Math.max.apply no meu computador. Veja https://jsben.ch/JPOyL.
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;
};
Se seus arrays contêm strings em vez de números, você também precisa convertê-los em números. O código abaixo faz isso, mas deixa o código cerca de 10 vezes mais lento na minha máquina. Veja https://jsben.ch/uPipD.
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;
};
Resposta #5
resumo
// 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];
}
}
solução MDN
A documentação oficial do MDN sobre Math.max() já aborda essa questão:
A função a seguir usa Function.prototype.apply() para encontrar o elemento máximo em um array numérico.
getMaxOfArray([1, 2, 3])é equivalente aMath.max(1, 2, 3), mas você pode usargetMaxOfArray()em arrays construídos programaticamente de qualquer tamanho.function getMaxOfArray(numArray) { return Math.max.apply(null, numArray); }Ou com o novo operador spread, obter o máximo de um array se torna muito mais fácil.
var arr = [1, 2, 3]; var max = Math.max(...arr);
Tamanho máximo de um array
De acordo com a MDN, as soluções apply e spread tinham uma limitação de 65536 que vinha do limite do número máximo de argumentos:
Mas cuidado: ao usar apply dessa maneira, você corre o risco de exceder o limite de comprimento de argumentos do motor JavaScript. As consequências de aplicar uma função com muitos argumentos (pense em mais de dezenas de milhares de argumentos) variam entre os motores (JavaScriptCore tem um limite de argumentos incorporado de 65536), porque o limite (e também a natureza de qualquer comportamento de pilha excessivamente grande) não é especificado. Alguns motores lançarão uma exceção. De forma mais perniciosa, outros limitarão arbitrariamente o número de argumentos realmente passados à função aplicada. Para ilustrar este último caso: se tal motor tivesse um limite de quatro argumentos (os limites reais são, claro, significativamente maiores), seria como se os argumentos 5, 6, 2, 3 tivessem sido passados para apply nos exemplos acima, em vez do array completo.
Eles até fornecem uma solução híbrida que na verdade não tem um bom desempenho em comparação com outras soluções. Veja o teste de desempenho abaixo para mais detalhes.
Em 2019, o limite real é o tamanho máximo da pilha de chamadas. Para navegadores de desktop modernos baseados no Chromium, isso significa que quando se trata de encontrar mínimo/máximo com apply ou spread, praticamente o tamanho máximo para arrays de apenas números é ~120000. Acima disso, ocorrerá um estouro de pilha e o seguinte erro será lançado:
RangeError: Tamanho máximo da pilha de chamadas excedido
Com o script abaixo (baseado neste post do blog), ao capturar esse erro você pode calcular o limite para o seu ambiente específico.
Atenção! Executar este script leva tempo e, dependendo do desempenho do seu sistema, pode deixar seu navegador/sistema lento ou travar!
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;
}
}Desempenho em grandes arrays
Com base no teste no comentário de EscapeNetscape, eu criei alguns benchmarks que testam 5 métodos diferentes em um array de apenas números aleatórios com 100000 itens.
Em 2019, os resultados mostram que o loop padrão (que aliás não tem limitação de tamanho) é o mais rápido em todos os casos. apply e spread vêm logo em seguida, depois muito mais tarde a solução híbrida da MDN e, por último, reduce como o mais lento.
Quase todos os testes deram os mesmos resultados, exceto por um em que o spread, de alguma forma, acabou sendo o mais lento.
Se você aumentar seu array para ter 1 milhão de itens, as coisas começam a quebrar e você fica com o loop padrão como uma solução rápida e reduce como uma mais lenta.
Benchmark JSPerf
Benchmark JSBen
Benchmark JSBench.me
Código-fonte de referência
var testArrayLength = 100000
var testArray = Array.from({length: testArrayLength}, () => Math.floor(Math.random() * 2000000));
// ES6 spread
Math.min(...testArray);
Math.max(...testArray);
// reduce
testArray.reduce(function(a, b) {
return Math.max(a, b);
});
testArray.reduce(function(a, b) {
return Math.min(a, b);
});
// apply
Math.min.apply(Math, testArray);
Math.max.apply(Math, testArray);
// standard loop
let max = testArray[0];
for (let i = 1; i < testArrayLength; ++i) {
if (testArray[i] > max) {
max = testArray[i];
}
}
let min = testArray[0];
for (let i = 1; i < testArrayLength; ++i) {
if (testArray[i] < min) {
min = testArray[i];
}
}
// MDN hibrid soltuion
// Source: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/apply#Using_apply_and_built-in_functions
function minOfArray(arr) {
var min = Infinity;
var QUANTUM = 32768;
for (var i = 0, len = arr.length; i < len; i += QUANTUM) {
var submin = Math.min.apply(null, arr.slice(i, Math.min(i + QUANTUM, len)));
min = Math.min(submin, min);
}
return min;
}
minOfArray(testArray);
function maxOfArray(arr) {
var max = -Infinity;
var QUANTUM = 32768;
for (var i = 0, len = arr.length; i < len; i += QUANTUM) {
var submax = Math.max.apply(null, arr.slice(i, Math.max(i + QUANTUM, len)));
max = Math.max(submax, max);
}
return max;
}
maxOfArray(testArray);Resposta #6
Se você é paranoico como eu sobre usar Math.max.apply (o que pode causar erros quando recebe grandes arrays, de acordo com o MDN), tente isto:
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);
});
}
Ou, em 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));
}
As funções anônimas são infelizmente necessárias (em vez de usar Math.max.bind(Math)) porque reduce não passa apenas a e b para sua função, mas também i e uma referência ao próprio array, então precisamos garantir que não tentemos chamar max sobre esses também.
Resposta #7
Métodos Alternativos Min/Máx
Os métodos Math.min e Math.max são ótimos para obter os itens mínimos e máximos de uma coleção de itens. No entanto, é importante estar ciente de algumas armadilhas que podem surgir com eles.
Usá-los com um array contendo um grande número de itens (mais de ~10⁷ itens, dependendo do navegador do usuário) provavelmente vai travar e gerar a seguinte mensagem de erro:
const arr = Array.from(Array(1000000).keys());
Math.min(arr);
Math.max(arr);
RangeError não capturado: tamanho máximo da pilha de chamadas excedido
Alguns navegadores podem retornar um valor NaN em vez disso. Pode ser uma maneira melhor de lidar com erros, mas ainda não resolve o problema.
Em vez disso, para números muito grandes, considere usar algo assim:
function maxValue(arr) {
return arr.reduce((max, val) => max > val ? max : val)
}
const arr = Array.from(Array(1000000).keys());
console.log(maxValue(arr)); // 999999Melhor tempo de execução:
function maxValue(arr) {
let max = arr[0];
for (let val of arr) {
if (val > max) {
max = val;
}
}
return max;
}
const arr = Array.from(Array(1000000).keys());
console.log(maxValue(arr)); // 999999Obtenha tanto o Mínimo quanto o Máximo:
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] });
}
const arr = Array.from(Array(1000000).keys());
console.log(getMinMax(arr)); // {"min":0,"max":999999}Melhor tempo de execução*:
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 };
}
const arr = Array.from(Array(1000000).keys());
console.log(getMinMax(arr)); // {"min":0,"max":999999}* Testado com 1.000.000 de itens:
Apenas para referência, o tempo de execução da 1ª função (na minha máquina) foi de 15,84ms contra 2ª função com apenas 4,32ms.
Resposta #8
Duas maneiras são mais curtas e fáceis:
let arr = [2, 6, 1, 0]
Forma 1:
let max = Math.max.apply(null, arr)
Forma 2:
let max = arr.reduce(function(a, b) {
return Math.max(a, b);
});
Resposta #9
.apply é frequentemente usado quando a intenção é invocar uma função variádica com uma lista de valores de argumentos, por exemplo.
A função Math.max([value1[,value2, ...]]) retorna o maior de zero ou mais números.
Math.max(10, 20); // 20
Math.max(-10, -20); // -10
Math.max(-10, 20); // 20
O método Math.max() não permite que você passe um array. Se você tiver uma lista de valores da qual precisa obter o maior, normalmente você chamaria essa função usando Function.prototype.apply(), por exemplo.
Math.max.apply(null, [10, 20]); // 20
Math.max.apply(null, [-10, -20]); // -10
Math.max.apply(null, [-10, 20]); // 20
No entanto, a partir do ECMAScript 6 você pode usar o operador spread:
O operador spread permite que uma expressão seja expandida em lugares onde múltiplos argumentos (para chamadas de função) ou múltiplos elementos (para literais de array) são esperados.
Usando o operador spread, o acima pode ser reescrito da seguinte maneira:
Math.max(...[10, 20]); // 20
Math.max(...[-10, -20]); // -10
Math.max(...[-10, 20]); // 20
Ao chamar uma função usando o operador variádico, você pode até adicionar valores adicionais, por exemplo.
Math.max(...[10, 20], 50); // 50
Math.max(...[-10, -20], 50); // 50
Bônus:
O operador spread permite que você use a sintaxe literal de matriz para criar novas matrizes em situações onde, no ES5, você precisaria recorrer a código imperativo, usando uma combinação de push, splice, etc.
let foo = ['b', 'c'];
let bar = ['a', ...foo, 'd', 'e']; // ['a', 'b', 'c', 'd', 'e']
Resposta #10
Você faz isso estendendo o tipo Array:
Array.max = function( array ){
return Math.max.apply( Math, array );
};
Array.min = function( array ){
return Math.min.apply( Math, array );
};
Impulsionado daqui (por John Resig)
Resposta #11
Uma solução simples para encontrar o valor mínimo em um Array de elementos é usar a função do protótipo Array reduce:
A = [4,3,-9,-2,2,1];
A.reduce((min, val) => val < min ? val : min, A[0]); // returns -9
ou usando a função Math.Min() embutida do JavaScript (obrigado @Tenflex):
A.reduce((min,val) => Math.min(min,val), A[0]);
Isso define min como A[0] e, em seguida, verifica para A[1]...A[n] se é estritamente menor que o min atual. Se A[i] < min, então min é atualizado para A[i]. Quando todos os elementos do array tiverem sido processados, min é retornado como resultado.
EDITAR: Incluir posição do 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 }
Resposta #12
Para uma solução concisa e moderna, pode-se realizar uma operação reduce sobre o array, mantendo o controle dos valores mínimo e máximo atuais, de modo que o array seja iterado apenas uma vez (o que é ótimo). A atribuição por desestruturação é usada aqui para maior concisão.
let array = [100, 0, 50];
let [min, max] = array.reduce(([prevMin,prevMax], curr)=>
[Math.min(prevMin, curr), Math.max(prevMax, curr)], [Infinity, -Infinity]);
console.log("Min:", min);
console.log("Max:", max);Para encontrar apenas o mínimo ou o máximo, podemos realizar uma operação de redução de maneira muito semelhante, mas só precisamos acompanhar o valor ótimo anterior. Este método é melhor do que usar apply, pois não causará erros quando o array for grande demais para a pilha.
const arr = [-1, 9, 3, -6, 35];
//Only find minimum
const min = arr.reduce((a,b)=>Math.min(a,b), Infinity);
console.log("Min:", min);//-6
//Only find maximum
const max = arr.reduce((a,b)=>Math.max(a,b), -Infinity);
console.log("Max:", max);//35Resposta #13
Outros já deram algumas soluções nas quais eles aumentam o Array.prototype. Tudo o que eu quero nesta resposta é esclarecer se deve ser Math.min.apply( Math, array ) ou Math.min.apply( null, array ). Então, qual contexto deve ser usado, Math ou null?
Ao passar null como contexto para apply, o contexto será definido por padrão para o objeto global (o objeto window no caso de navegadores). Passar o objeto Math como contexto seria a solução correta, mas não fará mal passar null também. Aqui está um exemplo de quando null pode causar problemas, ao decorar a função Math.max:
// 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);
O acima lançará uma exceção porque this.foo será avaliado como window.foo, que é undefined. Se substituirmos null por Math, as coisas funcionarão como esperado e a string "foo" será exibida na tela (eu testei isso usando o Mozilla Rhino).
Você pode praticamente assumir que ninguém decorou Math.max, então, passar null funcionará sem problemas.
Resposta #14
Mais uma maneira de fazer isso:
var arrayMax = Function.prototype.apply.bind(Math.max, null);
Uso :
var max = arrayMax([2, 5, 1]);
Resposta #15
Estou surpreso que ninguém tenha mencionado a função reduce.
var arr = [1, 10, 5, 11, 2]
var b = arr.reduce(function(previous,current){
return previous > current ? previous:current
});
b => 11
arr => [1, 10, 5, 11, 2]
Resposta #16
Isso pode atender aos seus 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;
}
Resposta #17
https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/Math/max
function getMaxOfArray(numArray) {
return Math.max.apply(null, numArray);
}
var arr = [100, 0, 50];
console.log(getMaxOfArray(arr))isso funcionou para mim.
Resposta #18
Eu pensei em compartilhar minha solução simples e fácil de entender.
Para o mínimo:
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);E para o 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);Resposta #19
let array=[267, 306, 108] let longest=Math.max(...array);
Resposta #20
A melhor forma com Math.min(...array) e Math.max(...array)
Resposta #21
Para arrays grandes (~10⁷ elementos), Math.min e Math.max produzem um RangeError (Tamanho máximo da pilha de chamadas excedido) no node.js.
Para grandes arrays, uma solução rápida e suja é:
Array.prototype.min = function() {
var r = this[0];
this.forEach(function(v,i,a){if (v<r) r=v;});
return r;
};
Resposta #22
array.sort((a, b) => b - a)[0];
Fornece o valor máximo em um array de números.
array.sort((a, b) => a - b)[0];
Fornece o valor mínimo em um array de números.
let array = [0,20,45,85,41,5,7,85,90,111];
let maximum = array.sort((a, b) => b - a)[0];
let minimum = array.sort((a, b) => a - b)[0];
console.log(minimum, maximum)Resposta #23
Para um array contendo objetos em vez de números:
arr = [
{ name: 'a', value: 5 },
{ name: 'b', value: 3 },
{ name: 'c', value: 4 }
]
Você pode usar reduce para obter o elemento com o menor valor (min)
arr.reduce((a, b) => a.value < b.value ? a : b)
// { name: 'b', value: 3 }
ou o maior valor (máx)
arr.reduce((a, b) => a.value > b.value ? a : b)
// { name: 'a', value: 5 }
Resposta #24
Além de usar a função matemática max e min, outra função a usar é a função embutida sort(): aqui vamos nós
const nums = [12, 67, 58, 30].sort((x, y) =>
x - y)
let min_val = nums[0]
let max_val = nums[nums.length -1]


