1179 Stimmen

Finden Sie das Min/Max-Element eines Arrays in JavaScript

Wie kann ich leicht erhalten die minimale oder maximale Element eines JavaScript-Array?

Beispiel Pseudocode:

let array = [100, 0, 50]

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

178 Stimmen

Anmerkung: Mit ECMAScript 6 können Sie die neue Spread-Operator (drei Punkte: ... ) mit Math.max() wie diese: Math.max(...[2, 5, 16, 1]) . Siehe meine Antwort aus dem MDN-Dokumentation .

0 Stimmen

Hier ein Benchmark für einen Geschwindigkeitsvergleich der gebräuchlichsten Vorgehensweisen: jsben.ch/#/1QuTg

0 Stimmen

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

1096voto

Roatin Marth Punkte 22467

Wie wäre es, das eingebaute Array-Objekt zu erweitern, um Math.max / Math.min stattdessen:

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

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

Hier ist ein JSFiddle .

Das Erweitern der Built-Ins kann zu Kollisionen mit anderen Bibliotheken führen (einige sehen), daher ist es vielleicht besser, wenn Sie nur apply ing Math.xxx() direkt mit Ihrem Array verbinden:

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

Alternativ können Sie, sofern Ihr Browser ECMAScript 6 unterstützt, die Spread-Operator der ähnlich funktioniert wie der apply Methode:

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

2 Stimmen

Müsste es nicht heißen "return Math.max.apply( Math, this );" und nicht return Math.max.apply( null, this );

4 Stimmen

@HankH: vielleicht. Math.max ist wie eine "statische" Methode, so dass es keine nützliche this Instanz darin (hoffe ich). Angenommen, das ist wahr, dann würde der Aufruf im globalen Bereich erfolgen (d.h. window ), was gleichbedeutend ist mit der Übergabe von null als ersten Parameter für apply / call .

9 Stimmen

@HankH: vorbei null o Math o {} oder was auch immer an apply() o call() hat keinen Einfluss auf das Ergebnis. Math.max verweist nicht und sollte nicht verweisen this innerlich.

462voto

newspire Punkte 5904
var max_of_array = Math.max.apply(Math, array);

Für eine ausführliche Diskussion siehe: http://aaroncrane.co.uk/2008/11/javascript_max_api/

23 Stimmen

Was ist der Unterschied zwischen Math.max.apply(Math, array) y Math.max.apply(null, array) ? Im Blog heißt es: "...man muss auch überflüssigerweise wieder sagen, dass max gehört zu Math ...", aber es scheint, dass ich das nicht tun muss (indem ich das erste Argument von apply als null ).

17 Stimmen

@ziyuang Wenn Sie es so nennen Math.max(a,b) , Math wird als die this Wert, also könnte es sinnvoll sein, dasselbe zu tun, wenn man mit apply . Aber Math.max verwendet nicht die this Wert, Sie können also jeden beliebigen Wert übergeben.

350voto

Abdennour TOUMI Punkte 75271

Verwendung des Spreizungsoperators (ES6)

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

const array = [10, 2, 33, 4, 5];

console.log(
  Math.max(...array)
)

14 Stimmen

Diese Lösung wurde bereits angeboten von mehrere andere Antworten.

49 Stimmen

Math.max(...[]) = -Unendlich. hahaha

12 Stimmen

@DavidPortabella Ich weiß nicht, warum das lustig ist. So funktioniert es nach der Spezifikation : If no arguments are given, the result is -.

294voto

Linus Unnebäck Punkte 19658

Für große Arrays (~10 Elemente), Math.min y Math.max erzeugt in Node.js den folgenden Fehler.

BereichFehler: Maximale Größe des Aufrufstapels ü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 Sorgen um die Geschwindigkeit machen, ist der folgende Code ~3 mal schneller als Math.max.apply befindet sich auf meinem Computer. Siehe https://jsben.ch/JPOyL .

function arrayMin(arr) {
  var len = arr.length, min = Infinity;
  while (len--) {
    if (arr[len] < min) {
      min = arr[len];
    }
  }
  return min;
};

function arrayMax(arr) {
  var len = arr.length, max = -Infinity;
  while (len--) {
    if (arr[len] > max) {
      max = arr[len];
    }
  }
  return max;
};

Wenn Ihre Arrays Strings anstelle von Zahlen enthalten, müssen Sie diese ebenfalls in Zahlen umwandeln. Der folgende Code tut das, aber es verlangsamt den Code ~10 mal auf meinem Rechner. Siehe https://jsben.ch/uPipD .

function arrayMin(arr) {
  var len = arr.length, min = Infinity;
  while (len--) {
    if (Number(arr[len]) < min) {
      min = Number(arr[len]);
    }
  }
  return min;
};

function arrayMax(arr) {
  var len = arr.length, max = -Infinity;
  while (len--) {
    if (Number(arr[len]) > max) {
      max = Number(arr[len]);
    }
  }
  return max;
};

0 Stimmen

Zuweisen. min y max bis zum letzten Element und reduzieren Sie die Iterationen um 1 ( while(--len) ) ;)

0 Stimmen

@Venugopal dann brauchen Sie eine spezielle Prüfung, um festzustellen, ob das Array leer ist, und geben Sie +/- Infinity zurück

3 Stimmen

Seltsam... Ich ging auf die verlinkte Website ... und Tests in Firefox 51.0.0 / Mac OS X 10.12.0, die reduzieren-basierte Ansatz ist 30% langsamer als Schleife-basierte ... sehr unterschiedliche Ergebnisse

183voto

totymedli Punkte 26057

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

Le site offizielle MDN-Dokumente über Math.max() deckt dieses Thema bereits ab:

Die folgende Funktion verwendet Function.prototype.apply() um das maximale Element in einem numerischen Feld zu finden. getMaxOfArray([1, 2, 3]) ist gleichbedeutend mit Math.max(1, 2, 3) , aber Sie können getMaxOfArray() auf programmatisch konstruierte Arrays beliebiger Größe.

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

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

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

Maximale Größe eines Arrays

Laut MDN die apply und verbreitete Lösungen hatte eine Begrenzung auf 65536, die sich aus der Begrenzung der maximalen Anzahl von Argumenten ergibt:

Aber Vorsicht: Wenn Sie apply auf diese Weise verwenden, besteht die Gefahr, dass Sie das Limit für die Argumentlänge der JavaScript-Engine überschreiten. Die Folgen der Anwendung einer Funktion mit zu vielen Argumenten (denken Sie an mehr als Zehntausende von Argumenten) variieren je nach Engine ( JavaScriptCore hat ein fest kodiertes Argumentlimit von 65536 ), da der Grenzwert (und sogar die Art eines übermäßig großen Stapels) nicht spezifiziert ist. Einige Maschinen werden eine Ausnahme auslösen. Andere wiederum begrenzen willkürlich die Anzahl der Argumente, die tatsächlich an die angewandte Funktion übergeben werden. Zur Veranschaulichung des letzteren Falles: Wenn eine solche Engine ein Limit von vier Argumenten hätte (die tatsächlichen Limits sind natürlich wesentlich höher), wäre es so, als ob in den obigen Beispielen die Argumente 5, 6, 2, 3 an apply übergeben worden wären und nicht das gesamte Array.

Sie bieten sogar eine Hybridlösung an, die im Vergleich zu anderen Lösungen nicht wirklich leistungsfähig ist. Siehe Leistungstest unten für mehr.

Im Jahr 2019 wird die das tatsächliche Limit ist die maximale Größe des Aufrufstapels . Für moderne Chromium-basierte Desktop-Browser bedeutet dies, dass bei der Suche nach min/max mit apply oder verbreitet, Praktisch ist die maximale Größe für reine Zahlen-Arrays ~120000 . Darüber hinaus kommt es zu einem Stapelüberlauf und die folgende Fehlermeldung wird ausgegeben:

BereichFehler: Maximale Größe des Aufrufstapels überschritten

Mit dem folgenden Skript (basierend auf dieser Blogbeitrag ), können Sie durch Abfangen dieses Fehlers den Grenzwert für Ihre spezifische Umgebung berechnen.

Warnung! Die Ausführung dieses Skripts nimmt Zeit in Anspruch und kann je nach der Leistung Ihres Systems Ihren Browser/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 bei großen Arrays

Auf der Grundlage des Tests in EscapeNetscape Kommentar habe ich einige Benchmarks erstellt, die 5 verschiedene Methoden auf einem Zufallszahl nur Array mit 100000 Elementen .

Für 2019 zeigen die Ergebnisse, dass die Standardschleife (das übrigens keine Größenbeschränkung hat) ist überall am schnellsten. apply und verbreiten folgt dicht darauf, dann viel später die Hybridlösung von MDN, dann reduce als die langsamste.

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

Wenn Sie Ihr Array auf 1 Million Elemente erweitern, wird es unübersichtlich, und es bleibt nur noch die Standardschleife als schnelle Lösung und reduce als ein langsamerer.

JSPerf-Benchmark

jsperf.com benchmark results for different solutions to find the min/max item of an array

JSBen-Benchmark

jsben.com benchmark results for different solutions to find the min/max item of an array

JSBench.me-Benchmark

jsbench.me benchmark results for different solutions to find the min/max item of an array

Benchmark-Quellcode

var testArrayLength = 100000
var testArray = Array.from({length: testArrayLength}, () => Math.floor(Math.random() * 2000000));

// ES6 spread
Math.min(...testArray);
Math.max(...testArray);

// reduce
testArray.reduce(function(a, b) {
  return Math.max(a, b);
});
testArray.reduce(function(a, b) {
  return Math.min(a, b);
});

// apply
Math.min.apply(Math, testArray);
Math.max.apply(Math, testArray);

// standard loop
let max = testArray[0];
for (let i = 1; i < testArrayLength; ++i) {
  if (testArray[i] > max) {
    max = testArray[i];
  }
}

let min = testArray[0];
for (let i = 1; i < testArrayLength; ++i) {
  if (testArray[i] < min) {
    min = testArray[i];
  }
}

// MDN hibrid soltuion
// Source: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/apply#Using_apply_and_built-in_functions
function minOfArray(arr) {
  var min = Infinity;
  var QUANTUM = 32768;

  for (var i = 0, len = arr.length; i < len; i += QUANTUM) {
    var submin = Math.min.apply(null, arr.slice(i, Math.min(i + QUANTUM, len)));
    min = Math.min(submin, min);
  }

  return min;
}

minOfArray(testArray);

function maxOfArray(arr) {
  var max = -Infinity;
  var QUANTUM = 32768;

  for (var i = 0, len = arr.length; i < len; i += QUANTUM) {
    var submax = Math.max.apply(null, arr.slice(i, Math.max(i + QUANTUM, len)));
    max = Math.max(submax, max);
  }

  return max;
}

maxOfArray(testArray);

0 Stimmen

Wenn Sie Typescript verwenden, wird der gezeigte Spread-Operator kompiliert zu Math.max.apply(Math, arr) für 'max'-Kompatibilität.

2 Stimmen

Ebenfalls von MDN: "beide verbreiten (...) y apply wird entweder fehlschlagen oder das falsche Ergebnis zurückgeben, wenn das Array zu viele Elemente hat [...] Die reduzierte Lösung hat dieses Problem nicht." Beim Testen von Chrome, FF, Edge und IE11 scheint es, dass es für ein Array mit bis zu 100k Werten in Ordnung ist. (Getestet auf Win10 und den neuesten Browsern: Chrome 110k, Firefox 300k, Edge 400k, IE11 150k).

0 Stimmen

Dies ist eine sehr langsame Methode, was wäre, wenn das Feld Tausende von Elementen hätte?

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X