Suchen Sie das min / max-Element eines Arrays in JavaScript

779

Wie kann ich einfach das Min- oder Max-Element eines JavaScript-Arrays erhalten?

Beispiel Pseudocode:

let array = [100, 0, 50]

array.min() //=> 0
array.max() //=> 100
HankH
quelle
93
Hinweis: Mit ECMAScript 6 Sie den neuen verwenden können Spread Operator (drei Punkte: ...) mit Math.max()wie folgt aus : Math.max(...[2, 5, 16, 1]). Siehe meine Antwort aus der MDN-Dokumentation .
Totymedli
1
Markieren Sie eine Antwort als akzeptiert.
Alex
Hier ein Benchmark für einen Geschwindigkeitsvergleich der gängigsten Methoden: jsben.ch/#/1QuTg
EscapeNetscape
es6 ist im Grunde hervorragend! :)
datdinhquoc
Ohne ES6 Math.max.apply(null, [2,5,16,1])
Tomer

Antworten:

828

Wie wäre es, wenn Sie das integrierte Array-Objekt erweitern, um Math.max/ Math.minstattdessen zu verwenden:

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

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

Hier ist eine JSFiddle .

Die Einbauten vermehren können mit anderen Bibliotheken verursachen Kollisionen (einige see), so können Sie mit nur bequemer apply‚ing Math.xxx()direkt auf Ihrem Array:

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

Angenommen, Ihr Browser unterstützt ECMAScript 6, können Sie alternativ den Spread-Operator verwenden, der ähnlich wie die applyMethode funktioniert :

var min = Math.min( ...arr ),
    max = Math.max( ...arr );
Roatin Marth
quelle
8
@HankH: Weitergeben nulloder Mathoder {}oder was auch immer apply()oder call()hat keinen Einfluss auf das Ergebnis. Math.maxverweist nicht und sollte auch nicht thisintern referenzieren .
Roatin Marth
31
Als C # -Programmierer benötige ich stark typisierte Fragen.
ChaosPandion
7
Ich habe nur einen jQuery-Fehler mit dem obigen Code geteilt, für dessen Debugging ich lange gebraucht habe. Ein jquery-Array funktioniert auf allen Geräten außer dem iPad. Ich musste das Array in ein echtes natives Array konvertieren, damit es funktioniert. Betroffen nur das einzelne Gerät aus irgendeinem GrundMath.max.apply(null, $.makeArray(array));
Forrest
11
Ich habe abgestimmt, weil der vorgeschlagene Ansatz O (n) Speicher im Stapelrahmen verbraucht und infolgedessen auf großen Arrays abstürzt. In meinem Fall reichten gerade mal 130000 Nummern aus, um nodejs zum Absturz zu bringen.
Alexey Timanovsky
14
Erweitern Sie solche eingebauten Prototypen nicht. Es geht nicht nur um Konflikte mit anderen Bibliotheken. Es geht auch um das Potenzial, das der Browser selbst in Zukunft für eine .maxoder eine .minMethode bietet . Perfekt realistisches Szenario: Sie verwenden diese Antwort. Im Jahr 2016 ES7 oder ES8 spec Array.maxund Array.min. Im Gegensatz zu dieser Version arbeiten sie mit Zeichenfolgen. Ihr zukünftiger Kollege versucht, mit der jetzt gut dokumentierten nativen .max()Methode die alphabetisch neueste Zeichenfolge in einem Array abzurufen, erhält dies jedoch auf mysteriöse Weise NaN. Stunden später findet sie diesen Code, führt a aus git blameund verflucht Ihren Namen.
Mark Amery
362
var max_of_array = Math.max.apply(Math, array);

Eine vollständige Diskussion finden Sie unter: http://aaroncrane.co.uk/2008/11/javascript_max_api/

Zeitung
quelle
13
Was ist der Unterschied zwischen Math.max.apply(Math, array)und Math.max.apply(null, array)? Der Blog sagt "... du musst auch redundant noch einmal sagen, was maxzu Math... gehört", aber es scheint, dass ich das nicht tun muss (indem ich das erste Argument von applyas setze null).
Ziyuang
9
@ziyuang Wenn Sie es wie aufrufen Math.max(a,b), Mathwird es als thisWert übergeben, daher ist es möglicherweise sinnvoll, dasselbe zu tun, wenn Sie mit aufrufen apply. Aber Math.maxnicht die Verwendung thisWert, so können Sie übergeben , was von Ihnen gewünschten Wert.
Oriol
199

Für große Arrays (~ 10⁷ Elemente) Math.minund Math.maxbeide erzeugen den folgenden Fehler in Node.js.

RangeError: Maximale Aufrufstapelgröße überschritten

Eine robustere Lösung besteht darin, nicht jedes Element zum Aufrufstapel hinzuzufügen, sondern stattdessen ein Array zu übergeben:

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

Wenn Sie sich Gedanken über die Geschwindigkeit machen, ist der folgende Code ~ 3-mal schneller Math.max.applyals auf meinem Computer. Siehe 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;
};

Wenn Ihre Arrays Zeichenfolgen anstelle von Zahlen enthalten, müssen Sie diese auch in Zahlen umwandeln. Der folgende Code macht das, aber er verlangsamt den Code auf meinem Computer ~ 10 Mal. Siehe 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
quelle
weise minund maxzum letzten Element zu und reduziere die Iterationen um 1 ( while(--len));)
Venugopal
@Venugopal dann brauchen Sie eine spezielle Überprüfung, um zu sehen, ob das Array leer ist und +/- Infinity
Linus Unnebäck
2
Seltsam ... Ich bin auf die verlinkte Website gegangen ... und habe in Firefox 51.0.0 / Mac OS X 10.12.0 getestet. Der reduktionsbasierte Ansatz ist 30% langsamer als der schleifenbasierte ... sehr unterschiedliche Ergebnisse
Pierpaolo Cira
2
very different results Sie haben dies 5 Jahre später
getan
1
Im Jahr 2019 ist die reduceLösung die langsamste. Selbst wenn Sie mit einem Array arbeiten, das Millionen von Elementen enthält, ist es besser, den Standard für die Schleife zu verwenden . Siehe meine Antwort für mehr.
Totymedli
152

Verwenden des Spread-Operators (ES6)

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

Abdennour TOUMI
quelle
8
Diese Lösung wurde bereits durch mehrere andere Antworten bereitgestellt .
Totymedli
15
Math.max (... []) = -Infinity. hahaha 😂😂😂
David Portabella
@ DavidPortabella nicht sicher, warum das lustig ist. So funktioniert es gemäß der Spezifikation :If no arguments are given, the result is -∞.
Patrick Roberts
3
Ja, ich meinte, dass die Javascript-Spezifikation schrecklich ist. Es scheint offensichtlich, dass die min ohne Zahlen nicht berechnet werden können. In anderen ernsthafteren Programmiersprachen wie Scala löst die Frage nach dem Minimum eines leeren Arrays eine Ausnahme aus.
David Portabella
3
Scala ist für Leute, die eine Maschine brauchen, um ihnen zu sagen, dass sie es falsch gemacht haben
thedanotto
106

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

MDN-Lösung

Die offiziellen MDN-DokumenteMath.max() behandeln dieses Problem bereits:

Die folgende Funktion verwendet Function.prototype.apply () , um das maximale Element in einem numerischen Array zu finden. getMaxOfArray([1, 2, 3])entspricht, Math.max(1, 2, 3)kann jedoch getMaxOfArray()für programmgesteuert erstellte Arrays jeder Größe verwendet werden.

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

Oder mit dem neuen Spread-Operator wird es viel einfacher, das Maximum eines Arrays zu erhalten.

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

Maximale Größe eines Arrays

Nach MDN die applyund Verbreitung Lösungen hatten eine Beschränkung von 65536 , die von der Grenze der maximalen Anzahl von Argumenten kam:

Beachten Sie jedoch, dass Sie bei der Verwendung von apply auf diese Weise das Risiko eingehen, das Argumentlängenlimit der JavaScript-Engine zu überschreiten. Die Konsequenzen der Anwendung einer Funktion mit zu vielen Argumenten (denken Sie an mehr als Zehntausende von Argumenten) variieren je nach Engine ( JavaScriptCore hat ein hartcodiertes Argumentlimit von 65536 ), da das Limit (in der Tat sogar die Art eines übermäßig großen Stapels) Verhalten) ist nicht spezifiziert. Einige Motoren lösen eine Ausnahme aus. Noch schädlicher ist, dass andere die Anzahl der Argumente, die tatsächlich an die angewendete Funktion übergeben werden, willkürlich begrenzen. Um diesen letzteren Fall zu veranschaulichen: Wenn eine solche Engine eine Grenze von vier Argumenten hätte (die tatsächlichen Grenzen sind natürlich erheblich höher), wäre es so, als ob die Argumente 5, 6, 2, 3 für die obigen Beispiele übergeben worden wären. eher als das gesamte Array.

Sie bieten sogar eine Hybridlösung, die im Vergleich zu anderen Lösungen keine wirklich gute Leistung aufweist. Weitere Informationen finden Sie im Leistungstest unten.

Im Jahr 2019 ist das tatsächliche Limit die maximale Größe des Aufrufstapels . Für moderne Chromium-basierte Desktop-Browser bedeutet dies, dass beim Finden von Min / Max mit applyoder Spread praktisch die maximale Größe für Arrays nur mit Zahlen ~ 120000 beträgt . Darüber hinaus kommt es zu einem Stapelüberlauf und der folgende Fehler wird ausgelöst:

RangeError: Maximale Aufrufstapelgröße überschritten

Mit dem folgenden Skript (basierend auf diesem Blog-Beitrag ) können Sie durch Abfangen dieses Fehlers das Limit für Ihre spezifische Umgebung berechnen.

Warnung! Das Ausführen dieses Skripts nimmt Zeit in Anspruch und kann je nach Leistung Ihres Systems Ihren Browser / Ihr System verlangsamen oder zum Absturz bringen!

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

Leistung auf großen Arrays

Basierend auf dem Test in EscapeNetscape 's Kommentar habe ich einige Benchmarks erstellt, die 5 verschiedene Methoden an einem Array nur mit Zufallszahlen mit 100000 Elementen testen .

Im Jahr 2019 zeigen die Ergebnisse, dass die Standardschleife (für die übrigens keine Größenbeschränkung gilt) überall die schnellste ist. applyund die Ausbreitung kommt dicht danach, dann viel später die Hybridlösung von MDNreduce als die langsamste.

Fast alle Tests ergaben die gleichen Ergebnisse, mit Ausnahme eines Tests, bei dem die Ausbreitung am langsamsten war.

Wenn Sie Ihr Array auf 1 Million Elemente erweitern, beginnen die Dinge zu brechen und Sie haben die Standardschleife als schnelle und reducelangsamere Lösung .

JSPerf-Benchmark

jsperf.com Benchmark-Ergebnisse für verschiedene Lösungen, um das Min / Max-Element eines Arrays zu finden

JSBen Benchmark

jsben.com-Benchmark-Ergebnisse für verschiedene Lösungen zum Ermitteln des Min / Max-Elements eines Arrays

JSBench.me Benchmark

jsbench.me Benchmark-Ergebnisse für verschiedene Lösungen, um das Min / Max-Element eines Arrays zu finden

Benchmark-Quellcode

totymedli
quelle
Wenn Sie Typoskript verwenden, wird der gezeigte Spread-Operator aus Gründen der Math.max.apply(Math, arr)maximalen Kompatibilität kompiliert .
Simon_Weaver
1
Ebenfalls von MDN: "Beide verbreiten sich (...)und applyschlagen entweder fehl oder geben das falsche Ergebnis zurück, wenn das Array zu viele Elemente enthält. [...] Die Reduktionslösung hat dieses Problem nicht." Beim Testen von Chrome, FF, Edge und IE11 scheint dies der Fall zu sein OK für ein Array mit bis zu 100.000 Werten. (Getestet unter Win10 und den neuesten Browsern: Chrome 110k, Firefox 300k, Edge 400k, IE11 150k).
Oriadam
Dies ist eine sehr langsame Methode. Was wäre, wenn das Array Tausende von Elementen enthalten würde?
Slava Fomin II
@SlavaFominII Ich habe die Antwort so erweitert, dass sie Arrays mit Tausenden von Elementen abdeckt.
Totymedli
68

Wenn Sie wie ich paranoid sind Math.max.apply(was bei großen Arrays gemäß MDN zu Fehlern führen kann ), versuchen Sie Folgendes:

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

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

Die anonymen Funktionen sind leider notwendig (anstatt zu verwenden, Math.max.bind(Math)weil reducenicht nur aund bzu seiner Funktion, sondern auch iund ein Verweis auf das Array selbst übergeben wird, müssen wir sicherstellen, dass wir nicht versuchen, diese auch aufzurufen max.

Daniel Buckmaster
quelle
Gibt es in Ihrem ES6-Beispiel einen Grund, warum Sie nicht einfach zurückkehren sollten Math.max(...array)?
Wojciech Bednarski
@WojciechBednarski Diese Seite scheint darauf hinzudeuten , dass die Verwendung des Spread-Operators mit der Übergabe eines Arrays identisch applyist und daher dieselben Nachteile hat (maximale Argumentgrenze).
Daniel Buckmaster
Danke dafür. Nur können Sie fehlende Klammer nach dem Reduzieren korrigieren:function arrayMax(array) { return array.reduce(function(a, b) { return Math.max(a, b); }); // <--------- missing ) }
Arkowsky
1
@DanielDietrich Ich denke, das Gleiche zu tun, Math.min()ohne Werte aufzurufen , gibt zurück Infinity, sodass diese Funktionen verwendet werden könnten reduce(..., Infinity), um diesem Verhalten zu entsprechen. Ich bevorzuge es jedoch, eine Ausnahme auszulösen (wie es derzeit der Fall ist), da es wahrscheinlich ein Fehler ist, das Minimum eines leeren Arrays zu nehmen.
Daniel Buckmaster
1
bisher ist reduzieren am langsamsten.
Алексей Лещук
40

.apply wird häufig verwendet, wenn die Absicht besteht, eine variable Funktion mit einer Liste von Argumentwerten aufzurufen, z

Die Math.max([value1[,value2, ...]])Funktion gibt die größte von null oder mehr Zahlen zurück.

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

Mit dieser Math.max()Methode können Sie kein Array übergeben. Wenn Sie eine Liste von Werten haben, von denen Sie die größten erhalten müssen, rufen Sie diese Funktion normalerweise mit Function.prototype.apply () auf , z

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

Doch wie der ECMAScript 6 können Sie die Verwendung Spread Betreiber :

Mit dem Spread-Operator kann ein Ausdruck an Stellen erweitert werden, an denen mehrere Argumente (für Funktionsaufrufe) oder mehrere Elemente (für Array-Literale) erwartet werden.

Mit dem Spread-Operator kann Folgendes wie folgt umgeschrieben werden:

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

Wenn Sie eine Funktion mit dem Variadic-Operator aufrufen, können Sie sogar zusätzliche Werte hinzufügen, z

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

Bonus:

Spread - Operator können Sie die Arrayliteral Syntax verwenden , um neue Felder in Situationen zu schaffen , in denen in ES5 Sie fallen zurück zu zwingenden Code benötigen würde, eine Kombination der Verwendung push, spliceetc.

let foo = ['b', 'c'];
let bar = ['a', ...foo, 'd', 'e']; // ['a', 'b', 'c', 'd', 'e']
Gajus
quelle
1
Ihr letztes Beispiel im Bonus wird concatvon den meisten Programmierern verwendet, da Sie damit einen einzelnen Linienstil beibehalten können.
Cody Allan Taylor
31

Zwei Wege sind kürzer und einfacher:

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

Weg 1 :

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

Weg 2 :

let max = arr.reduce(function(a, b) {
    return Math.max(a, b);
});
Hafizur Rahman
quelle
Achten Sie darauf, ob das Array leer ist - Sie erhalten eine negative Unendlichkeit, die möglicherweise nicht Ihren Wünschen entspricht. Wenn Sie es vorziehen, können 0Sie [0].concat(arr)oder mit Spread-Syntax [0, ...arr](anstelle von 'arr') verwenden
Simon_Weaver
Gibt es eine Möglichkeit, Nullwerte in Weg 1 auszuschließen?
bonbon.langes
22

Sie tun dies, indem Sie den Array-Typ erweitern:

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

Von hier aus verstärkt (von John Resig)

inkedmn
quelle
20

Eine einfache Lösung, um den Mindestwert für ein ArrayElement zu ermitteln, ist die Verwendung der ArrayPrototypfunktion reduce:

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

oder mit der in JavaScript integrierten Funktion Math.Min () (danke @Tenflex):

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

Dies setzt minauf A[0]und prüft dann, A[1]...A[n]ob es strikt kleiner als der Strom ist min. Wenn A[i] < mindann auf minaktualisiert wird A[i]. Wenn alle Array-Elemente verarbeitet wurden, minwird dies als Ergebnis zurückgegeben.

BEARBEITEN : Position des Mindestwerts einschließen:

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
quelle
3
A. Reduzieren ((min, val) => Math.min (min, val), A [0]); noch kürzer
Tenflex
Als Bonusfrage, wie kann nicht nur der minWert zurückgegeben werden, sondern auch seine Position im Array?
Stevek
@meshfields - Ich habe die Antwort aktualisiert.
Nicolas Lykke Iversen
15

Andere haben bereits einige Lösungen angegeben, die sie erweitern Array.prototype. Alles, was ich in dieser Antwort möchte, ist zu klären, ob es sein sollte Math.min.apply( Math, array )oder nicht Math.min.apply( null, array ). Welcher Kontext sollte also verwendet werden, Mathoder null?

Bei der Übergabe nullals Kontext an applywird der Kontext standardmäßig auf das globale Objekt (das windowObjekt bei Browsern) angewendet. Das MathObjekt als Kontext zu übergeben wäre die richtige Lösung, aber es wird auch nicht schaden, es zu übergeben null. Hier ist ein Beispiel, wenn nullbeim Dekorieren der Math.maxFunktion Probleme auftreten können:

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

Das Obige löst eine Ausnahme aus, da this.fooes als window.foo, was ist , ausgewertet wird undefined. Wenn wir ersetzen nullmit Math, wird es wie erwartet funktionieren und die Zeichenfolge „foo“ wird auf dem Bildschirm ausgegeben werden (Getestet habe ich diese mit Mozilla Rhino ).

Sie können so ziemlich davon ausgehen, dass niemand so dekoriert hat, Math.maxdass das Übergeben nullohne Probleme funktioniert.

Ionuț G. Stan
quelle
2
Punkt genommen. Aber warum sollte jemand dekorieren Foo.staticMethodund referenzieren this? Wäre das nicht ein Fehler im Design des Dekorateurs? (es sei denn natürlich waren sie wollen den globalen Bereich verweisen und wollen bleiben unabhängig von der JavaScript - Engine verwendet wird, zB Rhino).
Roatin Marth
1
Die Spezifikation gibt explizit an, welche specced-Funktionen sich auf " diesen Wert" beziehen sollen (tatsächlich kommt dieser Ausdruck 125 Mal in der Spezifikation vor). Math.max, gemäß Spezifikation implementiert, wird nicht verwendet this. Wenn jemand Math.maxsolche überschreibt , die er verwendet this, hat er dafür gesorgt, dass sein Verhalten gegen die Spezifikation verstößt, und Sie sollten scharfe Gegenstände auf ihn werfen. Sie sollten diese Möglichkeit nicht mehr codieren als die Möglichkeit, dass jemand getauscht hat, Math.maxund Math.minfür den Lulz.
Mark Amery
15

Noch eine Möglichkeit:

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

Verwendungszweck:

var max = arrayMax([2, 5, 1]);
sbr
quelle
Kann jemand erklären, wie das funktioniert? Das ist ziemlich doof. Ist mein Verständnis richtig: arrayMax ist eine Funktion und wir binden etwas an eine Eigenschaft ihres Prototyps? Was ist das? Binden und hat jeder Prototyp es?
Sam
Sie können auschecken
sbr
14

Alternative Methoden


Die Methoden Math.minund Math.maxsind rekursive Operationen, die dem Aufrufstapel der JS-Engine hinzugefügt werden, und höchstwahrscheinlich ein Absturz für ein Array, das eine große Anzahl von Elementen enthält
(mehr als ~ 10⁷ Elemente, abhängig vom Browser des Benutzers).

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

Nicht erfasster RangeError: Maximale Aufrufstapelgröße überschritten

Verwenden Sie stattdessen Folgendes:

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

Oder mit besserer Laufzeit:

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

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

Oder um sowohl Min als auch Max zu bekommen:

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

Oder mit noch besserer Laufzeit *:

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

* Getestet mit 1.000.000 Elementen:
Nur als Referenz: Die Laufzeit der ersten Funktion (auf meinem Computer) betrug 15,84 ms gegenüber der zweiten Funktion mit nur 4,32 ms.

Lior Elrom
quelle
13

Dies kann Ihren Zwecken entsprechen.

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
quelle
Sie sollten Ihr v mit 'this [0]' initialisieren, falls keine Zahlen kleiner als 0 sind
jasonmw
Soll comparerin einem bestimmten Umfang aufgerufen werden? Denn wie es ist, verweist this[index]es undefinedjedes Mal.
Roatin Marth
Behoben, ich vergesse immer das Scoping auf Funktionsebene.
ChaosPandion
Oh jetzt, jetzt @Ionut G. Stan wird Sie für das gleiche "falsche Kontext" -Argument wie er kritisieren, da Ihr Standardvergleich ( Math.xxx) im globalen Bereich ausgeführt wird ...
Roatin Marth
Das mag wahr sein, aber die neue Funktionssignatur erfordert keinen Gültigkeitsbereich, da sie die 2 Objekte benötigt, die verglichen werden müssen.
ChaosPandion
12

Ich bin überrascht, dass niemand die Reduktionsfunktion erwähnt hat.

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]
Hengst_V
quelle
Beachten Sie: redu
1
Ich kann dies in der aktuellen Version von Chromium nicht verwenden.
PJSCopeland
9

Für große Arrays (~ 10⁷ Elemente) Math.minundMath.max erzeugt einen RangeError (maximale Aufrufstapelgröße überschritten) in node.js.

Für große Arrays ist eine schnelle und schmutzige Lösung:

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

Ich hatte das gleiche Problem, ich musste die Minimal- und Maximalwerte eines Arrays ermitteln, und zu meiner Überraschung gab es keine integrierten Funktionen für Arrays. Nachdem ich viel gelesen hatte, beschloss ich, die "Top 3" -Lösungen selbst zu testen:

  1. diskrete Lösung: eine FOR-Schleife, um jedes Element des Arrays mit dem aktuellen Maximal- und / oder Minimalwert zu vergleichen;
  2. APPLY-Lösung: Senden des Arrays an die internen Funktionen Math.max und / oder Math.min mithilfe von apply (null, array);
  3. REDUCE-Lösung: Wiederholen einer Überprüfung für jedes Element des Arrays mithilfe von reduct (Funktion).

Der Testcode war folgender:

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

Das Array A wurde mit 100.000 zufälligen Ganzzahlen gefüllt. Jede Funktion wurde 10.000 Mal unter Mozilla Firefox 28.0 auf einem Intel Pentium 4 2,99-GHz-Desktop mit Windows Vista ausgeführt. Die Zeiten sind in Sekunden angegeben und werden von der Funktion performance.now () abgerufen. Die Ergebnisse waren diese mit 3 Bruchstellen und Standardabweichung:

  1. Diskrete Lösung: Mittelwert = 0,161 s, sd = 0,078
  2. APPLY-Lösung: Mittelwert = 3,571 s, SD = 0,487
  3. REDUZIEREN Sie die Lösung: Mittelwert = 0,350 s, sd = 0,044

Die REDUCE-Lösung war 117% langsamer als die diskrete Lösung. Die APPLY-Lösung war die schlechtere, 2.118% langsamer als die diskrete Lösung. Außerdem funktioniert es, wie Peter bemerkte, nicht für große Arrays (ungefähr mehr als 1.000.000 Elemente).

Um die Tests abzuschließen, habe ich diesen erweiterten diskreten Code getestet:

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

Das Timing: Mittelwert = 0,218 s, SD = 0,094

Es ist also 35% langsamer als die einfache diskrete Lösung, ruft jedoch gleichzeitig sowohl den Maximal- als auch den Minimalwert ab (jede andere Lösung würde mindestens das Doppelte benötigen, um sie abzurufen). Sobald das OP beide Werte benötigte, wäre die diskrete Lösung die beste Wahl (selbst wenn zwei separate Funktionen, eine zur Berechnung des Maximums und eine zur Berechnung des Minimums, die zweitbeste, die REDUCE-Lösung, übertreffen würden).

Cyberknight
quelle
8

Sie können die folgende Funktion überall in Ihrem Projekt verwenden:

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

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

Und dann können Sie die Funktionen aufrufen, die das Array übergeben:

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

Der folgende Code funktioniert für mich:

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
quelle
7

Iterieren Sie durch und behalten Sie dabei den Überblick.

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

Dadurch bleibt min / max null, wenn das Array keine Elemente enthält. Setzt min und max in einem Durchgang, wenn das Array Elemente enthält.

Sie können Array auch mit rangeder oben beschriebenen Methode erweitern, um die Wiederverwendung zu ermöglichen und die Lesbarkeit zu verbessern. Eine funktionierende Geige finden Sie unter 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 }
};

Benutzt als

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

var range = arr.range();

console.log(range.min);
console.log(range.max);
Tvanfosson
quelle
@JordanDillonChapian Ich würde zustimmen, aber es wäre trivial, dies auf eine rangeFunktion zu erweitern, die der beste Weg wäre, um sowohl das Min als auch das Max gleichzeitig zu erhalten, IMO - wie ich es mit einem Update meiner Antwort getan habe.
Tvanfosson
6

Ich dachte, ich würde meine einfache und leicht verständliche Lösung teilen.

Für die 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);

Und für das Maximum:

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
quelle
Vielen Dank. Ich habe meine Antwort geändert.
Ionut Necula
Die Iteration ist immer noch falsch (Zugriff auf nicht vorhandene Eigenschaften).
Bergi
Was ist falsch, ich sehe nichts falsch. Können Sie bitte ein Beispiel anbieten?
Ionut Necula
1
Jetzt entsprechend geändert. Hoffe ich habe dich richtig verstanden.
Ionut Necula
6

Neben der Verwendung der mathematischen Funktionen max und min ist die integrierte Funktion sort () eine weitere zu verwendende Funktion: Los geht's

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

Einfaches Zeug, wirklich.

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
quelle
5

Hier ist eine Möglichkeit, den Maximalwert aus einem Array von Objekten abzurufen. Erstellen Sie eine Kopie (mit Slice), sortieren Sie die Kopie in absteigender Reihenfolge und greifen Sie zum ersten Element.

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
quelle
5

Verwenden von Math.max()oderMath.min()

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

Die folgende Funktion verwendet Function.prototype.apply(), um das maximale Element in einem numerischen Array zu finden. getMaxOfArray([1, 2, 3])entspricht, Math.max(1, 2, 3)kann jedoch getMaxOfArray()für programmgesteuert erstellte Arrays jeder Größe verwendet werden.

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

Oder mit dem neuen Spread-Operator wird es viel einfacher, das Maximum eines Arrays zu erhalten.

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

Die Lösung von ChaosPandion funktioniert, wenn Sie Prototyp verwenden. Wenn nicht, beachten Sie Folgendes:

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

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

Das Obige gibt NaN zurück, wenn ein Array-Wert keine Ganzzahl ist. Sie sollten daher einige Funktionen erstellen, um dies zu vermeiden. Andernfalls funktioniert dies.

Jay
quelle
jeerose, warum hast du (Mathe, das) als Agrumente, wenn Roatin Marth nur (null, das) hat?
HankH
@HankH: Siehe meine Antwort auf Ihren Kommentar in einem Kommentar zu meiner eigenen Antwort.
Roatin Marth
1
Ich verstehe nicht, was Sie unter "ChaosPandions Lösung funktioniert, wenn Sie Prototyp verwenden" verstehen. Wie unterscheidet sich Ihre Lösung, außer dass Sie das MathObjekt als Kontext verwenden?
Ionuț G. Stan
Entschuldigung, ich meinte, wenn Sie den Prototyp erweitern, wird Ihr Prototyp funktionieren. Entschuldigung.
Jay
Also, was ist besser, Jeerose oder ChaosPandion?
HankH
3

Wenn Sie die Bibliothek sugger.js verwenden , können Sie wie vorgeschlagen arr.min () und arr.max () schreiben . Sie können auch Min- und Max-Werte von nicht numerischen Arrays abrufen.

min (Karte, alle = falsch) Gibt das Element im Array mit dem niedrigsten Wert zurück. map kann eine Funktion sein, die den zu prüfenden Wert abbildet, oder eine Zeichenfolge, die als Verknüpfung fungiert. Wenn alles wahr ist, werden alle Min-Werte in einem Array zurückgegeben.

max (map, all = false) Gibt das Element im Array mit dem größten Wert zurück. map kann eine Funktion sein, die den zu prüfenden Wert abbildet, oder eine Zeichenfolge, die als Verknüpfung fungiert. Wenn alles wahr ist, werden alle Maximalwerte in einem Array zurückgegeben.

Beispiele:

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

Bibliotheken wie Lo-Dash und underscore.js bieten ebenfalls ähnliche leistungsstarke Min- und Max-Funktionen:

Beispiel aus 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
quelle
3
let arr = [2,5,3,5,6,7,1];

let max = Math.max(...arr); // 7
let min = Math.min(...arr); // 1
UA_
quelle
2
Diese Lösung wurde bereits von mehreren anderen Antwortenden auf diese Frage bereitgestellt. Was fügt Ihre Antwort hinzu?
Nick
3

Versuchen

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

Für Math.min / max (+ anwenden) erhalten wir folgende Fehlermeldung:

Maximale Aufrufstapelgröße überschritten (Chrome 74.0.3729.131)

Kamil Kiełczewski
quelle