Encontre o elemento min / max de uma matriz em JavaScript

779

Como posso obter facilmente o elemento min ou max de uma matriz JavaScript?

Exemplo Psuedocode:

let array = [100, 0, 50]

array.min() //=> 0
array.max() //=> 100
HankH
fonte
93
Nota: Com ECMAScript 6, você pode usar o novo operador de propagação (três pontos: ...) com Math.max()como este: Math.max(...[2, 5, 16, 1]). Veja minha resposta feita na documentação do MDN .
totymedli
1
Considere marcar uma resposta como aceita.
1028 Alex
aqui uma referência para a comparação de velocidade das maneiras mais comuns de fazer isso: jsben.ch/#/1QuTg
EscapeNetscape
es6 é basicamente excelente! :)
datdinhquoc 29/01/19
Sem ES6 Math.max.apply(null, [2,5,16,1])
Tomer

Respostas:

828

Que tal aumentar o objeto Array interno para usar Math.max/ em Math.minvez disso:

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

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

Aqui está um JSFiddle .

Aumentando o built-ins podem causar colisões com outras bibliotecas (alguns SEE), assim você pode ser mais confortável com apenas apply'ing Math.xxx()diretamente para a matriz:

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

Como alternativa, supondo que seu navegador suporte o ECMAScript 6, você pode usar o operador de propagação, que funciona de maneira semelhante ao applymétodo:

var min = Math.min( ...arr ),
    max = Math.max( ...arr );
Roatin Marth
fonte
8
@HankH: passar nullou Mathou {}ou o que quer apply()ou call()não tem influência no resultado. Math.maxnão faz nem não deve fazer referência thisinternamente.
Roatin Marth 3/11/2009
31
Como programador de C #, eu preciso de perguntas fortemente tipadas.
ChaosPandion
7
Apenas compartilhando um erro do jQuery que eu estava cometendo com o código acima, que me levou muito tempo para depurar. Uma matriz jquery funciona bem em tudo, menos no iPad. Eu tive que converter a matriz em uma matriz nativa verdadeira para que funcionasse. Afetou apenas o dispositivo único por algum motivoMath.max.apply(null, $.makeArray(array));
Forrest
11
Eu diminuí a votação, porque a abordagem proposta consome O (n) memória no quadro da pilha e, como resultado, falha em matrizes grandes. No meu caso, apenas cerca de 130000 números foram suficientes para travar o nodejs.
Alexey Timanovsky
14
Não aumente protótipos internos como este. Não se trata apenas de conflitos com outras bibliotecas; também é sobre o potencial que o próprio navegador fornece .maxou .minmétodo no futuro. Cenário perfeitamente realista: você usa esta resposta. Em 2016, as especificações ES7 ou ES8 Array.maxe Array.min. Ao contrário desta versão, eles trabalham em strings. Seu futuro colega tenta obter a string mais recente em ordem alfabética em uma matriz com o .max()método nativo agora bem documentado , mas obtém misteriosamente NaN. Horas depois, ela encontra esse código, executa umgit blame e amaldiçoa seu nome.
Mark Amery
362
var max_of_array = Math.max.apply(Math, array);

Para uma discussão completa, consulte: http://aaroncrane.co.uk/2008/11/javascript_max_api/

jornal
fonte
13
Qual é a diferença entre Math.max.apply(Math, array)e Math.max.apply(null, array)? O blog diz "... você também tem que dizer redundantemente que maxpertence a Math...", mas parece que não preciso fazê-lo (definindo o primeiro argumento de applyas null).
precisa saber é o seguinte
9
@ziyuang Quando você chama assim Math.max(a,b), Mathé passado como thisvalor, portanto, pode fazer sentido fazer o mesmo ao ligar com apply. Mas Math.maxnão usa o thisvalor, para que você possa passar o valor que desejar.
Oriol
199

Para matrizes grandes (~ 10⁷ elementos) Math.mine Math.maxambas produzem o seguinte erro no Node.js.

RangeError: tamanho máximo da pilha de chamadas excedido

Uma solução mais robusta é não adicionar todos os elementos à pilha de chamadas, mas passar uma 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 );
  });
}

Se você está preocupado com a velocidade, o código a seguir é ~ 3 vezes mais rápido que o Math.max.applymeu computador. Consulte 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;
};

Se suas matrizes contiverem seqüências de caracteres em vez de números, você também precisará coagi-las em números. O código abaixo faz isso, mas diminui o código ~ 10 vezes na minha máquina. Consulte 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;
};
Linus Unnebäck
fonte
atribuir mine maxao último elemento e reduzir as iterações em 1 ( while(--len));)
Venugopal
@Venugopal então você precisa de um cheque especial para ver se a matriz está vazia e regresso +/- Infinito
Linus Unnebäck
2
Estranho ... fui ao site vinculado ... e testando no Firefox 51.0.0 / Mac OS X 10.12.0, a abordagem baseada em redução é 30% mais lenta que a baseada em loop ... resultados muito diferentes
Pierpaolo Cira
2
very different results você fez isso 5 anos depois)
Алексей Лещук
1
Em 2019, a reducesolução é a mais lenta. Mesmo se você trabalha com uma matriz que possui milhões de elementos, é melhor usar o padrão para loop . Veja minha resposta para mais.
totymedli
152

Usando o operador de spread (ES6)

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

Abdennour TOUMI
fonte
8
Essa solução já foi fornecida por várias outras respostas.
totymedli
15
Math.max (... []) =-Infinito. hahaha 😂😂😂
David Portabella
@DavidPortabella não sabe por que isso é engraçado. É assim que funciona, de acordo com a especificação :If no arguments are given, the result is -∞.
Patrick Roberts
3
sim, quis dizer que a especificação javascript é horrível. Parece óbvio que o número mínimo de números não pode ser calculado. Em outras linguagens de programação mais sérias, como Scala, solicitar o mínimo de uma matriz vazia gera uma exceção.
David Portabella
3
Scala é para pessoas que precisam de uma máquina para dizer-lhes que eles fizeram errado
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];
  }
}

Solução MDN

Os documentos oficiais do MDNMath.max() já abordam esse problema:

A função a seguir usa Function.prototype.apply () para encontrar o elemento máximo em uma matriz numérica. getMaxOfArray([1, 2, 3])é equivalente a Math.max(1, 2, 3), mas você pode usar getMaxOfArray()em matrizes construídas programaticamente de qualquer tamanho.

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

Ou com o novo operador spread , obter o máximo de uma matriz se torna muito mais fácil.

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

Tamanho máximo de uma matriz

De acordo com a MDN, as applysoluções e spread tinham uma limitação de 65536 que vinha do limite do número máximo de argumentos:

Mas tenha cuidado: ao usar o método aplicar dessa maneira, você corre o risco de exceder o limite de tamanho do argumento do mecanismo JavaScript. As conseqüências da aplicação de uma função com muitos argumentos (pense em mais de dezenas de milhares de argumentos) variam entre os mecanismos ( JavaScriptCore possui um limite de argumento codificado de 65536 ), porque o limite (na verdade, mesmo a natureza de qualquer pilha excessivamente grande) comportamento) não é especificado. Alguns motores lançam uma exceção. Mais perniciosamente, outros limitarão arbitrariamente o número de argumentos realmente transmitidos à função aplicada. Para ilustrar esse último caso: se um mecanismo desse tipo tivesse um limite de quatro argumentos (os limites reais são obviamente significativamente mais altos), seria como se os argumentos 5, 6, 2, 3 tivessem sido passados ​​para aplicar nos exemplos acima, em vez de toda a matriz.

Eles ainda fornecem uma solução híbrida que realmente não tem bom desempenho em comparação com outras soluções. Veja o teste de desempenho abaixo para mais informações.

Em 2019, o limite real é o tamanho máximo da pilha de chamadas . Para os modernos navegadores de desktop baseados em Chromium, isso significa que, quando se trata de encontrar min / max com applyou espalhar, praticamente o tamanho máximo para números apenas de matrizes é ~ 120000 . Acima disso, haverá um estouro de pilha e o seguinte erro será gerado:

RangeError: tamanho máximo da pilha de chamadas excedido

Com o script abaixo (com base nesta postagem do blog ), ao capturar esse erro, você pode calcular o limite para seu ambiente específico.

Atenção! A execução desse script leva tempo e, dependendo do desempenho do seu sistema, pode atrasar ou travar o seu 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;
  }
}

Desempenho em matrizes grandes

Com base no teste no comentário do EscapeNetscape , criei alguns benchmarks que testam 5 métodos diferentes em uma matriz apenas de número aleatório com 100000 itens .

Em 2019, os resultados mostram que o loop padrão (que BTW não tem limitação de tamanho) é o mais rápido em todos os lugares. applye a propagação ocorre logo depois, e muito mais tarde a solução híbrida da MDNreduce a mais lenta.

Quase todos os testes deram os mesmos resultados, exceto um em que a disseminação acabou sendo a mais lenta.

Se você aumentar sua matriz para ter 1 milhão de itens, as coisas começam a se deteriorar e você fica com o loop padrão como uma solução rápida e reducemais lenta.

Referência JSPerf

Resultados de benchmark do jsperf.com para diferentes soluções para encontrar o item mínimo / máximo de uma matriz

Referência JSBen

Resultados de benchmark do jsben.com para diferentes soluções para encontrar o item mínimo / máximo de uma matriz

Referência do JSBench.me

Resultados de benchmark do jsbench.me para diferentes soluções para encontrar o item mínimo / máximo de uma matriz

Código fonte de referência

totymedli
fonte
Se você estiver usando texto datilografado, o operador spread, como mostrado, é compilado para Math.max.apply(Math, arr)obter compatibilidade 'max'.
Simon_Weaver
1
Também do MDN: "espalhar (...)e applyfalhará ou retornará o resultado errado se a matriz tiver muitos elementos [...] A solução de redução não tiver esse problema". Testando Chrome, FF, Edge e IE11, parece que é ok para uma matriz de até 100k valores. (Testado no Win10 e nos navegadores mais recentes: Chrome 110k, Firefox 300k, Edge 400k, IE11 150k).
Oriadam
Este é um método muito lento, e se o array tivesse milhares de elementos?
Slava Fomin II
@SlavaFominII Estendi a resposta para cobrir matrizes com milhares de elementos.
totymedli
68

Se você é paranóico como eu sobre o uso Math.max.apply(o que pode causar erros quando são fornecidas matrizes grandes de acordo com o MDN ), tente o seguinte:

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, no 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));
}

Infelizmente, as funções anônimas são necessárias (em vez de usar Math.max.bind(Math)porque reducenão passa apenas ae bpara sua função, mas também ie uma referência à própria matriz, portanto, temos que garantir que não tentemos acessá max-las também.

Daniel Buckmaster
fonte
Seu exemplo do ES6, há alguma razão para não apenas retornar Math.max(...array)?
Wojciech Bednarski
@WojciechBednarski esta página parece sugerir que o uso do operador spread é o mesmo que passar uma matriz para applye, portanto, tem as mesmas desvantagens (limite máximo de argumentos).
Daniel Buckmaster
Obrigado por isso. Apenas você pode corrigir o suporte ausente depois de reduzir:function arrayMax(array) { return array.reduce(function(a, b) { return Math.max(a, b); }); // <--------- missing ) }
Arkowsky 28/09
1
@DanielDietrich Eu acho que fazer o equivalente, chamando Math.min()sem valores, retorna Infinity, então essas funções podem ser usadas reduce(..., Infinity)para combinar com esse comportamento. No entanto, prefiro lançar uma exceção (como ocorre atualmente), porque tomar o mínimo de uma matriz vazia parece provável que seja um erro.
precisa
1
até agora reduzir é o mais lento.
Aprovado em 19/04
40

.apply é frequentemente usado quando a intenção é invocar uma função variável com uma lista de valores de argumentos, por exemplo,

A Math.max([value1[,value2, ...]])função 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 Math.max()método não permite que você passe em uma matriz. Se você possui uma lista de valores dos quais precisa obter o maior, normalmente 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 de spread permite que uma expressão seja expandida em locais onde vários argumentos (para chamadas de função) ou vários elementos (para literais de matriz) 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ável, você pode até adicionar valores adicionais, por exemplo

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

Bônus:

Operador de propagação permite que você use a sintaxe literal matriz para criar novas matrizes em situações onde em ES5 você precisa para voltar a cair para 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']
Gajus
fonte
1
Seu último exemplo no bônus seria escrito concatpela maioria dos programadores, pois permite manter um estilo de linha única.
Cody Allan Taylor
31

Duas maneiras são mais curtas e fáceis:

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

Caminho 1 :

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

Caminho 2 :

let max = arr.reduce(function(a, b) {
    return Math.max(a, b);
});
Hafizur Rahman
fonte
Cuidado se a matriz estiver vazia - você receberá um infinito negativo que pode não ser o que você deseja. Se você preferir ficar 0você pode usar [0].concat(arr)ou com a sintaxe propagação [0, ...arr](no lugar de 'arr')
Simon_Weaver
existe uma maneira de excluir valores nulos na maneira 1?
bonbon.langes
22

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 a partir daqui (por John Resig)

inkedmn
fonte
20

Uma solução simples para encontrar o valor mínimo sobre um Arraydos elementos é usar a Arrayfunção prototype 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 () interna do JavaScript (obrigado @Tenflex):

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

Isso define mine A[0], em seguida, verifica A[1]...A[n]se é estritamente menor que o atual min. Se A[i] < minentão miné atualizado para A[i]. Quando todos os elementos da matriz tiverem sido processados, minserá retornado como resultado.

EDIT : Incluir posição 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 }
Nicolas Lykke Iversen
fonte
3
A.reduce ((min, val) => Math.min (min, val), A [0]); ainda mais curto
Tenflex
Como uma questão de bônus, como obter não apenas o minvalor retornado, mas também sua posição na matriz?
Stevek #
@esheshs - atualizei a resposta.
Nicolas Lykke Iversen
15

Outros já deram algumas soluções nas quais aumentam Array.prototype. Tudo o que quero nesta resposta é esclarecer se deveria ser Math.min.apply( Math, array )ou Math.min.apply( null, array ). Então, qual contexto deve ser usado Mathou null?

Ao passar nullcomo um contexto para apply, o contexto será padronizado para o objeto global (o windowobjeto no caso de navegadores). Passar o Mathobjeto como o contexto seria a solução correta, mas também não será prejudicial null. Aqui está um exemplo quando nullpode causar problemas ao decorar a Math.maxfunção:

// 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 exemplo acima lançará uma exceção porque this.fooserá avaliado como window.foo, o que é undefined. Se substituirmos nullpor Math, tudo funcionará conforme o esperado e a string "foo" será impressa na tela (eu testei isso usando o Mozilla Rhino ).

Você pode supor que ninguém o decorou Math.max, a passagem nullfuncionará sem problemas.

Ionuț G. Stan
fonte
2
Ponto tomado. No entanto, por que alguém decorar Foo.staticMethode fazer referência this? Isso não seria um erro no design do decorador? (a não ser, é claro, que eles quisessem fazer referência ao escopo global e desejassem permanecer independentes do mecanismo JavaScript em uso, por exemplo, Rhino).
Roatin Marth
1
A especificação é explícita sobre quais funções especificadas devem se referir a " esse valor" (na verdade, essa frase aparece 125 vezes na especificação). Math.max, implementado por especificação, não usa this. Se alguém sobrescreve de Math.maxtal forma que usa this, então eles fizeram seu comportamento violar as especificações e você deve atirar objetos pontiagudos contra eles. Você não deve codificar em torno dessa possibilidade da mesma forma que codificaria em torno da possibilidade de alguém ter trocado Math.maxe Math.minpelo lulz.
Mark Amery
15

Mais uma maneira de fazer isso:

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

Uso:

var max = arrayMax([2, 5, 1]);
sbr
fonte
Alguém pode explicar como isso funciona? Isso é muito narcótico. Meu entendimento está correto: arrayMax é uma função e vinculamos algo a uma propriedade de seu protótipo? O que é isso apply.bind e todo protótipo possui?
Sam
14

Métodos alternativos


Os métodos Math.mine Math.maxsão operações recursivas que estão sendo adicionadas à pilha de chamadas do mecanismo JS e provavelmente travam em uma matriz que contém um grande número de itens
(mais de ~ 10 itens, depende do navegador do usuário).

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

RangeError não capturado: tamanho máximo da pilha de chamadas excedido

Em vez disso, use algo assim:

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

Ou com melhor tempo de execução:

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

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

Ou, para obter Min e 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] });
}

Ou com tempo de execução ainda melhor *:

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

* Testado com 1.000.000 itens:
Apenas para referência, o tempo de execução da 1ª função (na minha máquina) foi 15,84ms vs 2ª função, com apenas 4,32ms.

Lior Elrom
fonte
13

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;
}
ChaosPandion
fonte
você deve inicializar o seu v com 'isto [0]' em caso nenhum número são menores do que 0
jasonmw
É comparersuposto ser chamado em algum âmbito específico? Porque como é referencia this[index]que é undefinedsempre.
Roatin Marth 3/11/2009
Corrigido, sempre esqueço o escopo do nível de função.
ChaosPandion
Oh agora, agora @Ionut G. Stan vai criticar você para o mesmo argumento "contexto errado", como ele me fez, desde o seu comparador padrão ( Math.xxx) será executado no escopo global ...
Roatin Marth
Isso pode ser verdade, mas a nova assinatura de função não requer escopo, pois leva dois objetos que precisam ser comparados.
ChaosPandion 03/11/2009
12

Estou surpreso por não ter mencionado a função de redução.

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]
Stallion_V
fonte
Esteja ciente: reduzir () é suportada a partir IE9, consulte developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/...
Paul Gobée
1
Não consigo usar isso na versão atual do Chromium.
PJSCopeland
9

Para matrizes grandes (~ 10⁷ elementos) Math.mine Math.maxgera um RangeError (tamanho máximo da pilha de chamadas excedido) no node.js.

Para matrizes grandes, 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;
};
Pedro
fonte
8

Eu tinha o mesmo problema, precisava obter os valores mínimo e máximo de uma matriz e, para minha surpresa, não havia funções internas para matrizes. Depois de ler muito, decidi testar as 3 principais soluções:

  1. solução discreta: um loop FOR para verificar todos os elementos da matriz em relação ao valor máximo e / ou mínimo atual;
  2. Solução APPLY: enviando o array para as funções internas Math.max e / ou Math.min usando apply (null, array);
  3. Solução REDUCE: repetindo uma verificação em todos os elementos da matriz usando reduzir (função).

O código de teste era o seguinte:

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

A matriz A foi preenchida com 100.000 números inteiros aleatórios, cada função foi executada 10.000 vezes no Mozilla Firefox 28.0 em um desktop Intel Pentium 4 2.99GHz com Windows Vista. Os tempos são em segundos, recuperados pela função performance.now (). Os resultados foram estes, com 3 dígitos fracionários e desvio padrão:

  1. Solução discreta: média = 0,161s, dp = 0,078
  2. APLICAR a solução: média = 3,571s, sd = 0,487
  3. REDUZIR a solução: média = 0,350s, sd = 0,044

A solução REDUCE foi 117% mais lenta que a solução discreta. A solução APPLY foi a pior, 2.118% mais lenta que a solução discreta. Além disso, como Peter observou, ele não funciona para grandes matrizes (cerca de mais de 1.000.000 de elementos).

Além disso, para concluir os testes, testei esse código discreto estendido:

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

O tempo: média = 0,218s, sd = 0,094

Portanto, é 35% mais lento que a solução discreta simples, mas recupera os valores máximo e mínimo de uma vez (qualquer outra solução levaria pelo menos duas vezes o valor para recuperá-los). Uma vez que o OP necessitasse de ambos os valores, a solução discreta seria a melhor escolha (mesmo que duas funções separadas, uma para calcular o máximo e outra para calcular o mínimo, elas superassem o segundo melhor, a solução REDUCE).

Cyberknight
fonte
8

Você pode usar a seguinte função em qualquer lugar do seu projeto:

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

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

E então você pode chamar as funções que passam pela matriz:

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

O código a seguir funciona para mim:

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); });
jaydip jadhav
fonte
7

Repita, mantendo o controle enquanto avança.

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

Isso deixará o mínimo / máximo nulo se não houver elementos na matriz. Definirá min e max em uma passagem se a matriz tiver algum elemento.

Você também pode estender a matriz com um rangemétodo usando o descrito acima para permitir a reutilização e melhorar a legibilidade. Veja um violino em 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);
tvanfosson
fonte
@JordanDillonChapian Eu concordo, mas seria trivial estender isso para uma rangefunção que seria a melhor maneira de obter o mínimo e o máximo ao mesmo tempo IMO - como fiz com uma atualização para minha resposta.
224146 TJRJ
6

Pensei em compartilhar minha solução simples e fácil de entender.

Para o 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);

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

Ionut Necula
fonte
Obrigado. Eu mudei minha resposta.
Ionut Necula 13/10
A iteração ainda está incorreta (acessando propriedades não existentes).
Bergi 13/10/16
O que está errado, não vejo nada errado. Você pode dar um exemplo, por favor?
Ionut Necula 13/10
1
Modificado de acordo agora. Espero ter entendido você corretamente.
Ionut Necula 13/10
6

Além de usar a função matemática max e min, outra função a ser usada é a função interna de sort (): aqui vamos nós

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

Coisas simples, realmente.

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());
Brian
fonte
5

Aqui está uma maneira de obter o valor máximo de uma matriz de objetos. Crie uma cópia (com fatia), depois ordene a cópia em ordem decrescente e pegue o primeiro item.

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; 
Ben
fonte
5

Usando Math.max()ouMath.min()

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

A função a seguir usa Function.prototype.apply()para encontrar o elemento máximo em uma matriz numérica. getMaxOfArray([1, 2, 3])é equivalente a Math.max(1, 2, 3), mas você pode usar getMaxOfArray()em matrizes construídas programaticamente de qualquer tamanho.

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

Ou com o novo operador spread, obter o máximo de uma matriz se torna muito mais fácil.

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

A solução do ChaosPandion funciona se você estiver usando o protoype. Caso contrário, considere o seguinte:

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

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

O exemplo acima retornará NaN se um valor da matriz não for um número inteiro; portanto, você deve criar alguma funcionalidade para evitar isso. Caso contrário, isso funcionará.

Jay
fonte
jeerose, por que você tem (matemática, isso) como argumentos quando Roatin Marth só tem (nulo, isso)?
HankH
@HankH: veja minha resposta ao seu comentário em um comentário à minha própria resposta.
Roatin Marth 3/11/2009
1
Não entendo o que você quer dizer com "a solução do ChaosPandion funciona se você estiver usando o protoype". Qual é a diferença da sua solução, exceto que você está usando o Mathobjeto como contexto?
Ionuţ G. Stan
Desculpe, eu quis dizer que se você estender o protótipo, o seu funcionará. Desculpas.
jay
Então, qual é o melhor, jeerose ou ChaosPandion?
HankH
3

Se você usar a biblioteca sugar.js , poderá escrever arr.min () e arr.max () conforme sugerido. Você também pode obter valores mínimo e máximo de matrizes não numéricas.

min (map, all = false) Retorna o elemento na matriz com o valor mais baixo. map pode ser uma função que mapeia o valor a ser verificado ou uma string que atua como um atalho. Se tudo for verdadeiro, retornará todos os valores mínimos em uma matriz.

max (map, all = false) Retorna o elemento na matriz com o maior valor. map pode ser uma função que mapeia o valor a ser verificado ou uma string que atua como um atalho. Se tudo for verdadeiro, retornará todos os valores máximos em uma matriz.

Exemplos:

[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 e underscore.js também fornecem funções min e max poderosas similares:

Exemplo do 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 }
andersh
fonte
3
let arr = [2,5,3,5,6,7,1];

let max = Math.max(...arr); // 7
let min = Math.min(...arr); // 1
UA_
fonte
2
Esta solução já foi fornecida por vários outros respondedores a esta pergunta. O que sua resposta adiciona?
Nick
3

Tentar

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 (+ aplicar), obtemos o erro:

Tamanho máximo da pilha de chamadas excedido (Chrome 74.0.3729.131)

Kamil Kiełczewski
fonte