Trova l'elemento min / max di un array in JavaScript


779

Come posso ottenere facilmente l'elemento minimo o massimo di un array JavaScript?

Esempio Psuedocode:

let array = [100, 0, 50]

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

93
Nota: Con ECMAScript 6 è possibile utilizzare il nuovo operatore di diffusione (tre punti: ...) con Math.max()in questo modo: Math.max(...[2, 5, 16, 1]). Vedi la mia risposta fatta dalla documentazione MDN .
totymedli,

1
Considera di contrassegnare una risposta come accettata.
Alex,

qui un punto di riferimento per un confronto veloce dei modi più comuni per farlo: jsben.ch/#/1QuTg
EscapeNetscape

es6 è sostanzialmente fantastico! :)
datdinhquoc

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

Risposte:


828

Che ne dici di aumentare l'oggetto Array incorporato per usare Math.max/ Math.mininvece:

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

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

Ecco un JSFiddle .

Aumentare le built-in può causare collisioni con altre librerie (alcuni vedono), così si può essere più a suo agio con il proprio apply'ing Math.xxx()per l'array direttamente:

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

In alternativa, supponendo che il tuo browser supporti ECMAScript 6, puoi utilizzare l' operatore spread che funziona in modo simile al applymetodo:

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

8
@HankH: passare nullo Matho {}o qualunque altra cosa apply()o call()non influire sul risultato. Math.maxnon fa né dovrebbe fare riferimento thisinternamente.
Roatin Marth,

31
Come programmatore C # ho bisogno di domande fortemente dattiloscritte.
ChaosPandion,

7
Stavo solo condividendo un errore jQuery che stavo facendo con il codice sopra che mi ha richiesto molto tempo per il debug. Un array jquery funziona perfettamente su tutto tranne che sull'iPad. Ho dovuto convertire l'array in un vero array nativo per farlo funzionare. Ha interessato il solo dispositivo per qualche motivoMath.max.apply(null, $.makeArray(array));
Forrest il

11
Ho effettuato il downgrade, perché l'approccio proposto consuma memoria O (n) nel frame dello stack e, di conseguenza, si arresta in modo anomalo su array di grandi dimensioni. Nel mio caso, sono stati sufficienti circa 130000 numeri per bloccare i nodijs.
Alexey Timanovsky,

14
Non aumentare prototipi integrati come questo. Non si tratta solo di conflitti con altre biblioteche; riguarda anche il potenziale che il browser stesso fornirà un metodo .maxo .minin futuro. Scenario perfettamente realistico: usi questa risposta. Nel 2016, ES7 o ES8 specifiche Array.maxe Array.min. A differenza di questa versione, funzionano sulle stringhe. Il tuo futuro collega cerca di ottenere la stringa alfabetica più recente in un array con il .max()metodo nativo ora ben documentato , ma ottiene misteriosamente NaN. Ore dopo, trova questo codice, esegue un git blamee maledice il tuo nome.
Mark Amery,

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

Per una discussione completa, consultare: http://aaroncrane.co.uk/2008/11/javascript_max_api/


13
Qual è la differenza tra Math.max.apply(Math, array)e Math.max.apply(null, array)? Il blog dice "... devi anche dire ridondante di nuovo che maxappartiene a Math...", ma sembra che non debba farlo (impostando il primo argomento di applyas null).
ziyuang,

9
@ziyuang Quando lo chiami come Math.max(a,b), Mathviene passato come thisvalore, quindi potrebbe avere senso fare lo stesso quando chiami apply. Ma Math.maxnon usa il thisvalore, quindi puoi passare qualunque valore tu voglia.
Oriol,

199

Per array di grandi dimensioni (~ 10⁷ elementi) Math.mined Math.maxentrambi producono il seguente errore in Node.js.

RangeError: dimensione massima dello stack di chiamate superata

Una soluzione più solida è quella di non aggiungere tutti gli elementi allo stack di chiamate, ma invece di passare un 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 sei preoccupato per la velocità, il seguente codice è ~ 3 volte più veloce Math.max.applyrispetto al mio computer. Vedi 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 le tue matrici contengono stringhe anziché numeri, devi anche forzarle in numeri. Il codice seguente lo fa, ma rallenta il codice ~ 10 volte sulla mia macchina. Vedi 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;
};

assegnare mine maxper ultimo elemento e ridurre le iterazioni di 1 ( while(--len));)
Venugopal

@Venugopal quindi è necessario un controllo speciale per vedere se l'array è vuoto e restituire +/- Infinity
Linus Unnebäck

2
Strano ... Sono andato al sito Web collegato ... e testando in Firefox 51.0.0 / Mac OS X 10.12.0, l'approccio basato sulla riduzione è più lento del 30% rispetto al ciclo ... risultati molto diversi
Pierpaolo Cira

2
very different results lo hai fatto 5 anni dopo)
Алексей Лещук,

1
Nel 2019 la reducesoluzione è la più lenta. Anche se lavori con un array con milioni di elementi, è meglio usare lo standard per il ciclo . Vedi la mia risposta per di più.
totymedli,

152

Utilizzo dell'operatore spread (ES6)

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


8
Questa soluzione è stata già fornita da più altre risposte.
totymedli,

15
Math.max (... []) = -Infinity. hahaha 😂😂😂
David Portabella

@DavidPortabella non so perché sia ​​divertente. Funziona così secondo le specifiche :If no arguments are given, the result is -∞.
Patrick Roberts,

3
sì, intendevo dire che la specifica javascript è orribile. Sembra ovvio che il minimo di nessun numero non può essere calcolato. In altri linguaggi di programmazione più seri, come Scala, chiedere il minimo di un array vuoto genera un'eccezione.
David Portabella,

3
Scala è per le persone che hanno bisogno di una macchina per dire loro che hanno fatto male
19

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

Soluzione MDN

I documenti MDN ufficiali suMath.max() già trattano questo problema:

La seguente funzione utilizza Function.prototype.apply () per trovare l'elemento massimo in un array numerico. getMaxOfArray([1, 2, 3])è equivalente a Math.max(1, 2, 3), ma è possibile utilizzarlo getMaxOfArray()su array costruiti a livello di programmazione di qualsiasi dimensione.

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

O con il nuovo operatore di diffusione , ottenere il massimo da un array diventa molto più semplice.

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

Dimensione massima di un array

Secondo MDN le applysoluzioni e spread avevano una limitazione di 65536 che derivava dal limite del numero massimo di argomenti:

Ma attenzione: nell'uso di applicare in questo modo, si corre il rischio di superare il limite di lunghezza degli argomenti del motore JavaScript. Le conseguenze dell'applicazione di una funzione con troppi argomenti (si pensi a più di decine di migliaia di argomenti) variano a seconda dei motori ( JavaScriptCore ha un limite di argomenti hard-codificato di 65536 ), perché il limite (anzi persino la natura di uno stack eccessivamente grande comportamento) non è specificato. Alcuni motori genereranno un'eccezione. Più perniciosamente, altri limiteranno arbitrariamente il numero di argomenti effettivamente passati alla funzione applicata. Per illustrare quest'ultimo caso: se un tale motore avesse un limite di quattro argomenti (i limiti effettivi sono ovviamente significativamente più alti), sarebbe come se gli argomenti 5, 6, 2, 3 fossero stati passati per applicarsi negli esempi precedenti, piuttosto che l'array completo.

Forniscono persino una soluzione ibrida che in realtà non ha buone prestazioni rispetto ad altre soluzioni. Vedi il test delle prestazioni di seguito per ulteriori informazioni.

Nel 2019 il limite effettivo è la dimensione massima dello stack di chiamate . Per i moderni browser desktop basati su Chromium ciò significa che quando si tratta di trovare min / max con applyo diffondere, praticamente la dimensione massima per i numeri solo array è ~ 120000 . Al di sopra di questo, ci sarà un overflow dello stack e verrà generato il seguente errore:

RangeError: dimensione massima dello stack di chiamate superata

Con lo script seguente (basato su questo post del blog ), rilevando tale errore puoi calcolare il limite per il tuo ambiente specifico.

Avvertimento! L'esecuzione di questo script richiede tempo e, a seconda delle prestazioni del sistema, potrebbe rallentare o bloccare il browser / 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;
  }
}

Prestazioni su array di grandi dimensioni

Sulla base del test nel commento di EscapeNetscape ho creato alcuni parametri di riferimento che testano 5 metodi diversi su un array solo di numeri casuali con 100000 articoli .

Nel 2019, i risultati mostrano che il loop standard (che BTW non ha limiti di dimensione) è il più veloce ovunque. applye la diffusione lo segue da vicino, quindi molto più tardi la soluzione ibrida di MDN e quindi reducela più lenta.

Quasi tutti i test hanno dato gli stessi risultati, tranne uno in cui la diffusione è risultata essere la più lenta.

Se si aumenta l'array per avere 1 milione di elementi, le cose iniziano a rompersi e si rimane con il loop standard come soluzione rapida e reducecome più lenta.

Benchmark JSPerf

Risultati benchmark jsperf.com per diverse soluzioni per trovare l'elemento min / max di un array

Benchmark JSBen

Risultati del benchmark jsben.com per diverse soluzioni per trovare l'elemento min / max di un array

Benchmark JSBench.me

Risultati benchmark jsbench.me per diverse soluzioni per trovare l'elemento min / max di un array

Codice sorgente benchmark


Se stai usando il dattiloscritto, l'operatore di diffusione come mostrato è compilato Math.max.apply(Math, arr)per la massima compatibilità.
Simon_Weaver,

1
Anche da MDN: "entrambi si diffondono (...)e applyfalliranno o restituiranno il risultato sbagliato se l'array ha troppi elementi [...] La soluzione di riduzione non presenta questo problema" Test di Chrome, FF, Edge e IE11 sembra che sia ok per un array con valori fino a 100k. (Testato su Win10 e browser più recenti: Chrome 110k, Firefox 300k, Edge 400k, IE11 150k).
oriadam,

Questo è un metodo molto lento, e se l'array avesse migliaia di elementi?
Slava Fomin II

@SlavaFominII Ho esteso la risposta in modo da coprire le matrici con migliaia di elementi.
totymedli

68

Se sei paranoico come me sull'utilizzo Math.max.apply(che potrebbe causare errori quando vengono dati array di grandi dimensioni secondo MDN ), prova questo:

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

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

Le funzioni anonime sono purtroppo necessarie (invece di usare Math.max.bind(Math)perché reducenon solo passa ae balla sua funzione, ma anche ie un riferimento all'array stesso, quindi dobbiamo assicurarci di non provare a richiamare anche maxquelle.


Il tuo esempio ES6, c'è qualche motivo per cui non tornare e basta Math.max(...array)?
Wojciech Bednarski,

@WojciechBednarski questa pagina sembra suggerire che l'utilizzo dell'operatore spread è lo stesso del passaggio di un array a apply, e quindi ha gli stessi aspetti negativi (limite massimo dell'argomento).
Daniel Buckmaster,

Grazie per questo. Solo puoi correggere la parentesi mancante dopo la riduzione:function arrayMax(array) { return array.reduce(function(a, b) { return Math.max(a, b); }); // <--------- missing ) }
Arkowsky,

1
@DanielDietrich Immagino che fare l'equivalente, chiamare Math.min()senza valori, ritorni Infinity, quindi queste funzioni potrebbero usare reduce(..., Infinity)per abbinare quel comportamento. Preferisco comunque generare un'eccezione (come accade attualmente), poiché è probabile che prendere il minimo di un array vuoto sia un errore.
Daniel Buckmaster,

1
finora ridurre è il più lento.
Алексей Лещук,

40

.apply viene spesso utilizzato quando si intende invocare una funzione variadica con un elenco di valori argomento, ad es

La Math.max([value1[,value2, ...]])funzione restituisce il massimo di zero o più numeri.

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

Il Math.max()metodo non consente di passare in un array. Se hai un elenco di valori di cui hai bisogno per ottenere il massimo, normalmente chiameresti questa funzione usando Function.prototype.apply () , ad es.

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

Tuttavia, a partire da ECMAScript 6 è possibile utilizzare l' operatore spread :

L'operatore spread consente di espandere un'espressione in punti in cui sono previsti più argomenti (per chiamate di funzione) o più elementi (per valori letterali di array).

Utilizzando l'operatore spread, quanto sopra può essere riscritto come tale:

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

Quando si chiama una funzione utilizzando l'operatore variadic, è anche possibile aggiungere valori aggiuntivi, ad es

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

Bonus:

Operatore di diffusione consente di utilizzare la sintassi letterale array per creare nuovi array in situazioni in cui in ES5 si avrebbe bisogno di ripiegare in codice imperativo, utilizzando una combinazione di push, spliceecc

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

1
Il tuo ultimo esempio nel bonus verrà scritto usando concatdalla maggior parte dei programmatori perché ti consente di mantenere uno stile a linea singola.
Cody Allan Taylor,

31

Due modi sono più brevi e facili:

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

Modo 1 :

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

Modo 2 :

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

Fai attenzione se l'array è vuoto: otterrai un infinito negativo che potrebbe non essere quello che desideri. Se preferisci ottenere 0puoi usare [0].concat(arr)o con la sintassi diffusa [0, ...arr](al posto di 'arr')
Simon_Weaver

c'è un modo per escludere valori null nel modo 1?
bonbon.langes

22

Lo fai estendendo il tipo di array:

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

Potenziato da qui (di John Resig)


20

Una soluzione semplice per trovare il valore minimo su uno Arraydegli elementi è utilizzare la Arrayfunzione prototipo reduce:

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

o usando la funzione Math.Min () integrata di JavaScript (grazie a @Tenflex):

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

Questo imposta minsu A[0]e quindi verifica A[1]...A[n]se è strettamente inferiore alla corrente min. Se A[i] < minquindi minviene aggiornato a A[i]. Quando tutti gli elementi dell'array sono stati elaborati, minviene restituito come risultato.

EDIT : include posizione di valore minimo:

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]); ancora più breve
Tenflex

Come domanda bonus, come avere non solo il minvalore restituito, ma anche la sua posizione nell'Array?
stevek,

@meshfields - Ho aggiornato la risposta.
Nicolas Lykke Iversen il

15

Altri hanno già fornito alcune soluzioni in cui aumentano Array.prototype. Tutto ciò che voglio in questa risposta è chiarire se dovrebbe essere Math.min.apply( Math, array )o Math.min.apply( null, array ). Quindi quale contesto dovrebbe essere usato Matho null?

Quando si passa nullcome contesto a apply, il contesto verrà automaticamente impostato sull'oggetto globale (l' windowoggetto nel caso dei browser). Passare l' Mathoggetto come contesto sarebbe la soluzione corretta, ma non danneggerà nullneanche il passaggio . Ecco un esempio quando nullpotrebbe causare problemi, quando si decora la Math.maxfunzione:

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

Quanto sopra genererà un'eccezione perché this.fooverrà valutata come window.foo, ovvero undefined. Se sostituiamo nullcon Math, le cose funzioneranno come previsto e la stringa "pippo" verrà stampato sullo schermo (Ho provato questo utilizzando Mozilla Rhino ).

Puoi praticamente supporre che nessuno abbia decorato Math.maxcosì, il passaggio nullfunzionerà senza problemi.


2
Punto preso. Tuttavia, perché qualcuno dovrebbe decorareFoo.staticMethod e fare riferimento this? Non sarebbe un errore nel design del decoratore? (a meno che, naturalmente, non volessero fare riferimento all'ambito globale e desiderino rimanere indipendenti dal motore JavaScript utilizzato, ad esempio Rhino).
Roatin Marth,

1
La specifica è esplicita su quali funzioni specificate dovrebbero riferirsi a " questo valore" (in effetti, quella frase appare 125 volte nella specifica). Math.max, implementato per specifica, non utilizza this. Se qualcuno Math.maxesegue l' override in modo tale che venga utilizzatothis , allora hanno fatto in modo che il suo comportamento violi le specifiche e dovresti lanciare oggetti taglienti contro di loro. Non dovresti codificare intorno a quella possibilità più di quanto non codificheresti intorno alla possibilità che qualcuno abbia scambiato Math.maxe Math.minper il lulz.
Mark Amery,

15

Un altro modo per farlo:

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

Uso:

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

Qualcuno può spiegare come funziona? Questo è piuttosto stupido. La mia comprensione è corretta: arrayMax è una funzione e associamo qualcosa a una proprietà del suo prototipo? Cos'è questo apply.bind e ogni prototipo ce l'ha?
Sam,


14

Metodi alternativi


I metodi Math.mine Math.maxsono entrambe operazioni ricorsive che vengono aggiunte allo stack di chiamate del motore JS e molto probabilmente si arrestano in modo anomalo per un array che contiene un numero elevato di elementi
(più di ~ 10⁷ elementi, dipende dal browser dell'utente).

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

Errore intervallo non rilevato: dimensione massima dello stack di chiamate superata

Invece, usa qualcosa del genere:

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

O con un tempo di esecuzione migliore:

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

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

O per ottenere sia Min che 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 runtime ancora migliore *:

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

* Testato con 1.000.000 di articoli:
solo per riferimento, il tempo di esecuzione della 1a funzione (sulla mia macchina) era di 15,84 ms contro la 2a funzione con solo 4,32 ms.


13

Questo può soddisfare i tuoi scopi.

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

dovresti inizializzare la tua v con 'this [0]' nel caso in cui nessun numero sia inferiore a 0
jasonmw,

È comparersupposto di essere chiamato in qualche specifico campo di applicazione? Perché come è riferimenti this[index]che è undefinedogni volta.
Roatin Marth,

Risolto, dimentico sempre l'ambito a livello di funzione.
ChaosPandion,

Oh ora, ora @Ionut G. Stan ti criticherà per lo stesso argomento "contesto sbagliato" che mi ha fatto, dal momento che il tuo comparatore predefinito ( Math.xxx) funzionerà nell'ambito globale ...
Roatin Marth,

Questo può essere vero, ma la nuova firma della funzione non richiede alcun ambito in quanto accetta i 2 oggetti che devono essere confrontati.
ChaosPandion,



9

Per array di grandi dimensioni (~ 10⁷ elementi) Math.mine Math.maxgenera un RangeError (dimensione massima dello stack di chiamate superata) in node.js.

Per array di grandi dimensioni, una soluzione rapida e sporca è:

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

8

Ho avuto lo stesso problema, avevo bisogno di ottenere i valori minimo e massimo di un array e, con mia sorpresa, non c'erano funzioni incorporate per gli array. Dopo aver letto molto, ho deciso di provare personalmente le "prime 3" soluzioni:

  1. soluzione discreta: un ciclo FOR per verificare ogni elemento dell'array rispetto al valore massimo e / o minimo corrente;
  2. Soluzione APPLY: invio dell'array alle funzioni interne di Math.max e / o Math.min mediante apply (null, array);
  3. Soluzione REDUCE: ricorrere a un controllo su ogni elemento dell'array usando la funzione di riduzione ().

Il codice di test era questo:

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

L'array A è stato riempito con 100.000 numeri interi casuali, ogni funzione è stata eseguita 10.000 volte su Mozilla Firefox 28.0 su un desktop Intel Pentium 4 2.99GHz con Windows Vista. I tempi sono in secondi, recuperati dalla funzione performance.now (). I risultati furono questi, con 3 cifre frazionarie e deviazione standard:

  1. Soluzione discreta: media = 0,161 s, sd = 0,078
  2. APPLICARE la soluzione: media = 3.571s, sd = 0.487
  3. Ridurre la soluzione: media = 0,350 s, sd = 0,044

La soluzione REDUCE era più lenta del 117% rispetto alla soluzione discreta. La soluzione APPLY era la peggiore, il 2,118% più lenta della soluzione discreta. Inoltre, come osservato da Peter, non funziona per array di grandi dimensioni (circa più di 1.000.000 di elementi).

Inoltre, per completare i test, ho testato questo codice esteso esteso:

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

Il tempismo: media = 0,218 s, sd = 0,094

Pertanto, è più lento del 35% rispetto alla semplice soluzione discreta, ma recupera contemporaneamente i valori massimo e minimo (qualsiasi altra soluzione richiederebbe almeno il doppio di quella per recuperarli). Una volta che l'OP aveva bisogno di entrambi i valori, la soluzione discreta sarebbe stata la scelta migliore (anche se due funzioni separate, una per il calcolo del massimo e un'altra per il calcolo del minimo, avrebbero sovraperformato la seconda migliore, la soluzione REDUCE).


8

È possibile utilizzare la seguente funzione in qualsiasi punto del progetto:

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

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

E quindi puoi chiamare le funzioni passando l'array:

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

8

Il seguente codice funziona per me:

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

Scorri, tenendo traccia di ciò che procedi.

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

Ciò lascerà null min / max se non ci sono elementi nell'array. Imposta min e max in un passaggio se l'array ha degli elementi.

È inoltre possibile estendere la matrice con un rangemetodo utilizzando quanto sopra per consentire il riutilizzo e migliorare la leggibilità. Guarda un violino funzionante su 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 }
};

Usato come

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

var range = arr.range();

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

@JordanDillonChapian Sono d'accordo, ma sarebbe banale estenderlo a una rangefunzione che sarebbe il modo migliore per ottenere sia il minimo che il massimo contemporaneamente IMO, come ho fatto con un aggiornamento alla mia risposta.
tvanfosson,

6

Ho pensato di condividere la mia soluzione semplice e di facile comprensione.

Per il minimo:

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 per il massimo:

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



Grazie. Ho cambiato la mia risposta.
Ionut Necula,

L'iterazione è ancora errata (accesso a proprietà inesistenti).
Bergi,

Cosa c'è che non va, non vedo nulla di sbagliato. Puoi offrire un esempio per favore?
Ionut Necula,

1
Modificato di conseguenza ora. Spero di averti capito correttamente.
Ionut Necula,

5

Roba semplice, davvero.

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

Ecco un modo per ottenere il valore massimo da una matrice di oggetti. Crea una copia (con slice), quindi ordina la copia in ordine decrescente e prendi il primo oggetto.

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

Utilizzando Math.max()oMath.min()

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

La seguente funzione utilizza Function.prototype.apply()per trovare l'elemento massimo in un array numerico. getMaxOfArray([1, 2, 3])è equivalente a Math.max(1, 2, 3), ma è possibile utilizzarlo getMaxOfArray()su array costruiti a livello di programmazione di qualsiasi dimensione.

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

O con il nuovo operatore di diffusione, ottenere il massimo da un array diventa molto più semplice.

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

5

Oltre a utilizzare la funzione matematica max e min, un'altra funzione da utilizzare è la funzione integrata di sort (): eccoci

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

4

La soluzione di ChaosPandion funziona se stai usando il protoipo. In caso contrario, considerare questo:

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

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

Quanto sopra restituirà NaN se un valore di array non è un numero intero, quindi è necessario creare alcune funzionalità per evitarlo. Altrimenti funzionerà.


jeerose, perché hai (matematica, questo) come strumenti quando Roatin Marth ha solo (null, questo)?
HankH,

@HankH: vedi la mia risposta al tuo commento in un commento alla mia risposta.
Roatin Marth,

1
Non capisco cosa intendi con "La soluzione di ChaosPandion funziona se stai usando il protoipo". In che modo la tua soluzione è diversa, tranne per il fatto che stai usando l' Mathoggetto come contesto?
Ionuț G. Stan,

Scusa, intendevo dire che se estendi il prototipo il tuo funzionerà. Scuse.
jay

Quindi qual è meglio, jeerose o ChaosPandion?
HankH,

3

Se usi la libreria sugar.js , puoi scrivere arr.min () e arr.max () come suggerisci. È inoltre possibile ottenere valori min e max da matrici non numeriche.

min (map, all = false) Restituisce l'elemento nella matrice con il valore più basso. map può essere una funzione che mappa il valore da verificare o una stringa che funge da collegamento. Se tutto è vero, restituirà tutti i valori minimi in un array.

max (map, all = false) Restituisce l'elemento nella matrice con il valore più grande. map può essere una funzione che mappa il valore da verificare o una stringa che funge da collegamento. Se tutto è vero, restituirà tutti i valori massimi in un array.

Esempi:

[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"]

Le librerie come Lo-Dash e underscore.js offrono anche potenti funzioni min e max simili:

Esempio da 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
Questa soluzione è già stata fornita da più altri risponditori a questa domanda. Cosa aggiunge la tua risposta?
Nick

3

Provare

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

Per Math.min / max (+ apply) viene visualizzato l'errore:

Dimensione massima dello stack di chiamate superata (Chrome 74.0.3729.131)

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.