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
javascript
HankH
fonte
fonte
...
) comMath.max()
como este:Math.max(...[2, 5, 16, 1])
. Veja minha resposta feita na documentação do MDN .Math.max.apply(null, [2,5,16,1])
Respostas:
Que tal aumentar o objeto Array interno para usar
Math.max
/ emMath.min
vez disso: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
'ingMath.xxx()
diretamente para a matriz:Como alternativa, supondo que seu navegador suporte o ECMAScript 6, você pode usar o operador de propagação, que funciona de maneira semelhante ao
apply
método:fonte
null
ouMath
ou{}
ou o que querapply()
oucall()
não tem influência no resultado.Math.max
não faz nem não deve fazer referênciathis
internamente.Math.max.apply(null, $.makeArray(array));
.max
ou.min
método no futuro. Cenário perfeitamente realista: você usa esta resposta. Em 2016, as especificações ES7 ou ES8Array.max
eArray.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 misteriosamenteNaN
. Horas depois, ela encontra esse código, executa umgit blame
e amaldiçoa seu nome.Para uma discussão completa, consulte: http://aaroncrane.co.uk/2008/11/javascript_max_api/
fonte
Math.max.apply(Math, array)
eMath.max.apply(null, array)
? O blog diz "... você também tem que dizer redundantemente quemax
pertence aMath
...", mas parece que não preciso fazê-lo (definindo o primeiro argumento deapply
asnull
).Math.max(a,b)
,Math
é passado comothis
valor, portanto, pode fazer sentido fazer o mesmo ao ligar comapply
. MasMath.max
não usa othis
valor, para que você possa passar o valor que desejar.Para matrizes grandes (~ 10⁷ elementos)
Math.min
eMath.max
ambas produzem o seguinte erro no Node.js.Uma solução mais robusta é não adicionar todos os elementos à pilha de chamadas, mas passar uma matriz:
Se você está preocupado com a velocidade, o código a seguir é ~ 3 vezes mais rápido que o
Math.max.apply
meu computador. Consulte http://jsperf.com/min-and-max-in-array/2 .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 .
fonte
min
emax
ao último elemento e reduzir as iterações em 1 (while(--len)
);)very different results
você fez isso 5 anos depois)reduce
soluçã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.Usando o operador de spread (ES6)
Mostrar snippet de código
fonte
If no arguments are given, the result is -∞.
tl; dr
Solução MDN
Os documentos oficiais do MDN
Math.max()
já abordam esse problema:Tamanho máximo de uma matriz
De acordo com a MDN, as
apply
soluções e spread tinham uma limitação de 65536 que vinha do limite do número máximo de argumentos: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
apply
ou 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: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!
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.
apply
e 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
reduce
mais lenta.Referência JSPerf
Referência JSBen
Referência do JSBench.me
Código fonte de referência
Mostrar snippet de código
fonte
Math.max.apply(Math, arr)
obter compatibilidade 'max'.(...)
eapply
falhará 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).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:Ou, no ES6:
Infelizmente, as funções anônimas são necessárias (em vez de usar
Math.max.bind(Math)
porquereduce
não passa apenasa
eb
para sua função, mas tambémi
e uma referência à própria matriz, portanto, temos que garantir que não tentemos acessámax
-las também.fonte
Math.max(...array)
?apply
e, portanto, tem as mesmas desvantagens (limite máximo de argumentos).function arrayMax(array) { return array.reduce(function(a, b) { return Math.max(a, b); }); // <--------- missing ) }
Math.min()
sem valores, retornaInfinity
, então essas funções podem ser usadasreduce(..., 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..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.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 exemploNo entanto, a partir do ECMAScript 6, você pode usar o operador spread :
Usando o operador spread, o acima pode ser reescrito da seguinte maneira:
Ao chamar uma função usando o operador variável, você pode até adicionar valores adicionais, por exemplo
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.fonte
concat
pela maioria dos programadores, pois permite manter um estilo de linha única.Duas maneiras são mais curtas e fáceis:
Caminho 1 :
Caminho 2 :
fonte
0
você pode usar[0].concat(arr)
ou com a sintaxe propagação[0, ...arr]
(no lugar de 'arr')Você faz isso estendendo o tipo Array:
Impulsionado a partir daqui (por John Resig)
fonte
Uma solução simples para encontrar o valor mínimo sobre um
Array
dos elementos é usar aArray
função prototypereduce
:ou usando a função Math.Min () interna do JavaScript (obrigado @Tenflex):
Isso define
min
eA[0]
, em seguida, verificaA[1]...A[n]
se é estritamente menor que o atualmin
. SeA[i] < min
entãomin
é atualizado paraA[i]
. Quando todos os elementos da matriz tiverem sido processados,min
será retornado como resultado.EDIT : Incluir posição de valor mínimo:
fonte
min
valor retornado, mas também sua posição na matriz?Outros já deram algumas soluções nas quais aumentam
Array.prototype
. Tudo o que quero nesta resposta é esclarecer se deveria serMath.min.apply( Math, array )
ouMath.min.apply( null, array )
. Então, qual contexto deve ser usadoMath
ounull
?Ao passar
null
como um contexto paraapply
, o contexto será padronizado para o objeto global (owindow
objeto no caso de navegadores). Passar oMath
objeto como o contexto seria a solução correta, mas também não será prejudicialnull
. Aqui está um exemplo quandonull
pode causar problemas ao decorar aMath.max
função:O exemplo acima lançará uma exceção porque
this.foo
será avaliado comowindow.foo
, o que éundefined
. Se substituirmosnull
porMath
, 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 passagemnull
funcionará sem problemas.fonte
Foo.staticMethod
e fazer referênciathis
? 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).Math.max
, implementado por especificação, não usathis
. Se alguém sobrescreve deMath.max
tal forma que usathis
, 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 trocadoMath.max
eMath.min
pelo lulz.Mais uma maneira de fazer isso:
Uso:
fonte
Métodos alternativos
Os métodos
Math.min
eMath.max
sã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).
Em vez disso, use algo assim:
Ou com melhor tempo de execução:
Ou, para obter Min e Max:
Ou com tempo de execução ainda melhor *:
* 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.
fonte
Isso pode atender aos seus propósitos.
fonte
comparer
suposto ser chamado em algum âmbito específico? Porque como é referenciathis[index]
que éundefined
sempre.Math.xxx
) será executado no escopo global ...https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/Math/max
isso funcionou para mim.
fonte
Estou surpreso por não ter mencionado a função de redução.
fonte
Para matrizes grandes (~ 10⁷ elementos)
Math.min
eMath.max
gera um RangeError (tamanho máximo da pilha de chamadas excedido) no node.js.Para matrizes grandes, uma solução rápida e suja é:
fonte
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:
O código de teste era o seguinte:
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:
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:
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).
fonte
Você pode usar a seguinte função em qualquer lugar do seu projeto:
E então você pode chamar as funções que passam pela matriz:
fonte
O código a seguir funciona para mim:
fonte
Repita, mantendo o controle enquanto avança.
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
range
método usando o descrito acima para permitir a reutilização e melhorar a legibilidade. Veja um violino em http://jsfiddle.net/9C9fU/Usado como
fonte
range
funçã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.Pensei em compartilhar minha solução simples e fácil de entender.
Para o min:
E para o máximo:
fonte
for…in
enumerações em matrizes!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
fonte
Coisas simples, realmente.
fonte
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.
fonte
Usando
Math.max()
ouMath.min()
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 aMath.max(1, 2, 3)
, mas você pode usargetMaxOfArray()
em matrizes construídas programaticamente de qualquer tamanho.Ou com o novo operador spread, obter o máximo de uma matriz se torna muito mais fácil.
fonte
A solução do ChaosPandion funciona se você estiver usando o protoype. Caso contrário, considere o seguinte:
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á.
fonte
Math
objeto como contexto?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.
Exemplos:
Bibliotecas como Lo-Dash e underscore.js também fornecem funções min e max poderosas similares:
Exemplo do Lo-Dash:
fonte
fonte
Tentar
Mostrar snippet de código
Para Math.min / max (+ aplicar), obtemos o erro:
Mostrar snippet de código
fonte