Znajdź element min / max tablicy w JavaScript

778

Jak mogę łatwo uzyskać min. Lub maks. Element tablicy JavaScript?

Przykładowy kod Psuedocode:

let array = [100, 0, 50]

array.min() //=> 0
array.max() //=> 100
Hank
źródło
93
Uwaga: Z ECMAScript 6 można użyć nowego operatora spread (trzy kropki: ...) z Math.max()tak: Math.max(...[2, 5, 16, 1]). Zobacz moją odpowiedź wykonany z dokumentacją MDN .
totymedli
1
Rozważ zaznaczenie odpowiedzi jako zaakceptowanej.
Alex
tutaj punkt odniesienia dla porównania prędkości najpopularniejszych sposobów: jsben.ch/#/1QuTg
EscapeNetscape 25.10.16
es6 jest w zasadzie wspaniały! :)
datdinhquoc
Bez ES6 Math.max.apply(null, [2,5,16,1])
Tomer

Odpowiedzi:

827

Co powiesz na rozszerzenie wbudowanego obiektu Array do użycia Math.max/ Math.minzamiast:

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

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

Oto JSFiddle .

Rozszerzanie wbudowanych może powodować kolizje z innymi bibliotekami (niektóre patrz), więc możesz czuć się bardziej komfortowo z bezpośrednim applydostępem Math.xxx()do tablicy:

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

Alternatywnie, zakładając, że Twoja przeglądarka obsługuje ECMAScript 6, możesz użyć operatora rozprzestrzeniania, który działa podobnie do applymetody:

var min = Math.min( ...arr ),
    max = Math.max( ...arr );
Roatin Marth
źródło
8
@HankH: przekazanie nulllub Mathlub {}lub cokolwiek się apply()lub call()nie ma wpływu na wynik. Math.maxnie odnosi się ani nie powinien odnosić się thiswewnętrznie.
Roatin Marth
31
Jako programista C # wymagam silnie wpisywanych pytań.
ChaosPandion
7
Po prostu dzielę się błędem jQuery, który popełniłem z powyższym kodem, przez co debugowanie zajęło mi dużo czasu. Tablica jquery działa dobrze na wszystkim oprócz iPada. Musiałem przekonwertować tablicę na prawdziwą macierz natywną, aby działała. Z jakiegoś powodu wpłynęło to tylko na jedno urządzenieMath.max.apply(null, $.makeArray(array));
Forrest,
11
Odebrałem głos, ponieważ proponowane podejście zużywa pamięć O (n) w ramce stosu, aw rezultacie ulega awarii na dużych tablicach. W moim przypadku wystarczyło około 130000 numerów, aby rozbić nodejów.
Alexey Timanovsky
14
Nie rozszerzaj wbudowanych prototypów takich jak ten. Nie chodzi tylko o konflikty z innymi bibliotekami; ale także o potencjale że sama przeglądarka dostarcza .maxlub .minmetody w przyszłości. Idealnie realistyczny scenariusz: korzystasz z tej odpowiedzi. W 2016 r. Specyfikacja ES7 lub ES8 Array.maxi Array.min. W przeciwieństwie do tej wersji działają na ciągach znaków. Twój przyszły kolega próbuje pobrać najnowszy alfabetyczny ciąg do tablicy za pomocą dobrze udokumentowanej .max()metody natywnej , ale w tajemniczy sposób NaN. Kilka godzin później znajduje ten kod, uruchamia git blamei przeklina twoje imię.
Mark Amery
362
var max_of_array = Math.max.apply(Math, array);

Pełna dyskusja na stronie: http://aaroncrane.co.uk/2008/11/javascript_max_api/

gazeta
źródło
13
Jaka jest różnica między Math.max.apply(Math, array)i Math.max.apply(null, array)? Na blogu jest napisane: „… musisz także powtórnie powiedzieć, że maxnależy do Math…”, ale wydaje się, że nie muszę tego robić (ustawiając pierwszy argument applyas null).
ziyuang,
9
@ziyuang Gdy nazywasz to tak Math.max(a,b), Mathjest on przekazywany jako thiswartość, więc może to mieć sens, aby robić to samo, dzwoniąc z apply. Ale Math.maxnie używa tej thiswartości, więc możesz przekazać dowolną wartość, którą chcesz.
Oriol,
199

Dla dużych tablic (~ 10⁷ elementów) Math.mini Math.maxoba powodują następujący błąd w Node.js.

RangeError: Przekroczono maksymalny rozmiar stosu wywołań

Bardziej niezawodnym rozwiązaniem jest nie dodawanie każdego elementu do stosu wywołań, ale zamiast tego przekazywanie tablicy:

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

Jeśli obawiasz się o szybkość, poniższy kod jest ~ 3 razy szybszy niż Math.max.applyna moim komputerze. Zobacz 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;
};

Jeśli twoje tablice zawierają ciągi zamiast liczb, musisz również zmusić je do liczb. Poniższy kod to robi, ale spowalnia kod ~ 10 razy na moim komputerze. Zobacz 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
źródło
przypisz mini maxdo ostatniego elementu i zmniejsz iteracje o 1 ( while(--len));)
Venugopal
@Venugopal, a następnie potrzebujesz specjalnego sprawdzenia, czy tablica jest pusta, i zwróć +/- Infinity
Linus Unnebäck
2
Dziwne ... Poszedłem na połączoną stronę ... i testowałem w Firefoksie 51.0.0 / Mac OS X 10.12.0, podejście oparte na redukcji jest 30% wolniejsze niż oparte na pętli ... bardzo różne wyniki
Pierpaolo Cira
2
very different results zrobiłeś to 5 lat później)
Алексей Лещук
1
W 2019 r . reduceRozwiązanie jest najwolniejsze. Nawet jeśli pracujesz z tablicą zawierającą miliony elementów, lepiej jest użyć standardowej pętli for . Zobacz moją odpowiedź, aby uzyskać więcej.
totymedli
152

Korzystanie z operatora rozkładania (ES6)

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

Abdennour TOUMI
źródło
8
To rozwiązanie zostało już dostarczone przez wiele innych odpowiedzi.
totymedli 13.04.17
15
Math.max (... []) = -Nieskończoność. hahaha 😂😂😂
David Portabella
@DavidPortabella nie jestem pewien, dlaczego to śmieszne. Tak to działa zgodnie ze specyfikacją :If no arguments are given, the result is -∞.
Patrick Roberts
3
tak, miałem na myśli, że specyfikacja javascript jest okropna. Wydaje się oczywiste, że nie można obliczyć min bez liczb. W innych poważniejszych językach programowania, takich jak Scala, żądanie minimalnej pustej tablicy powoduje wyjątek.
David Portabella
3
Scala jest dla ludzi, którzy potrzebują maszyny, aby powiedzieć im, że zrobili to źle
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];
  }
}

Rozwiązanie MDN

W oficjalnych Docs MDN naMath.max() obejmuje już ten problem:

Poniższa funkcja używa Function.prototype.apply (), aby znaleźć maksymalny element w tablicy numerycznej. getMaxOfArray([1, 2, 3])jest równoważne Math.max(1, 2, 3), ale można używać getMaxOfArray()na programowo skonstruowanych tablicach o dowolnym rozmiarze.

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

Lub dzięki nowemu operatorowi rozkładania uzyskanie maksimum tablicy staje się znacznie łatwiejsze.

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

Maksymalny rozmiar tablicy

Według MDN się applyi rozprzestrzeniania rozwiązań miało ograniczenie 65536 dostarczonej z limitem maksymalnej liczby argumentów:

Ale uwaga: używając tej opcji, ryzykujesz przekroczenie limitu długości argumentów silnika JavaScript. Konsekwencje zastosowania funkcji z zbyt dużą liczbą argumentów (pomyśl więcej niż dziesiątki tysięcy argumentów) są różne w różnych silnikach ( JavaScriptCore ma zakodowany na stałe limit argumentów 65536 ), ponieważ limit (a nawet natura każdego nadmiernie dużego stosu zachowanie) jest nieokreślony. Niektóre silniki zgłoszą wyjątek. Bardziej szkodliwe jest, że inni dowolnie ograniczą liczbę argumentów faktycznie przekazanych do zastosowanej funkcji. Aby zilustrować ten ostatni przypadek: gdyby taki silnik miał limit czterech argumentów (rzeczywiste limity są oczywiście znacznie wyższe), byłoby tak, jakby argumenty 5, 6, 2, 3 zostały przekazane do zastosowania w powyższych przykładach, zamiast pełnej tablicy.

Zapewniają nawet rozwiązanie hybrydowe, które tak naprawdę nie ma dobrej wydajności w porównaniu z innymi rozwiązaniami. Zobacz test wydajności poniżej, aby uzyskać więcej.

W 2019 r. Rzeczywisty limit to maksymalny rozmiar stosu wywołań . W przypadku nowoczesnych przeglądarek stacjonarnych opartych na Chromium oznacza to, że jeśli chodzi o znalezienie min / max z applylub rozprzestrzeniania, praktycznie maksymalny rozmiar dla tablic tylko z liczbami wynosi ~ 120000 . Ponadto nastąpi przepełnienie stosu i zostanie zgłoszony następujący błąd:

RangeError: Przekroczono maksymalny rozmiar stosu wywołań

Za pomocą poniższego skryptu (na podstawie tego postu na blogu ), wychwytując ten błąd, możesz obliczyć limit dla określonego środowiska.

Ostrzeżenie! Uruchomienie tego skryptu zajmuje dużo czasu i w zależności od wydajności systemu może spowolnić lub zawiesić przeglądarkę / system!

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

Wydajność na dużych tablicach

W oparciu o test w komentarzu EscapeNetscape stworzyłem pewne testy porównawcze, które testują 5 różnych metod na tablicy z liczbami losowymi zawierającymi 100 000 elementów .

W 2019 r. Wyniki pokazują, że standardowa pętla (której BTW nie ma ograniczenia wielkości) jest wszędzie najszybsza. applyi rozprzestrzenia się po nim, a potem znacznie później hybrydowe rozwiązanie MDN reducejako najwolniejsze.

Prawie wszystkie testy dały takie same wyniki, z wyjątkiem jednego, w którym rozprzestrzenianie się okazało się być najwolniejsze.

Jeśli zwiększysz swoją tablicę, aby mieć milion przedmiotów, wszystko zacznie się psuć i pozostanie Ci standardowa pętla jako szybkie rozwiązanie i reducewolniejsze.

Test porównawczy JSPerf

Wyniki testu jsperf.com dla różnych rozwiązań w celu znalezienia min / max elementu tablicy

Test porównawczy JSBen

Wyniki testu porównawczego jsben.com dla różnych rozwiązań w celu znalezienia min / max elementu tablicy

Test porównawczy JSBench.me

Wyniki testu jsbench.me dla różnych rozwiązań, aby znaleźć pozycję min / max tablicy

Kod źródłowy testu porównawczego

totymedli
źródło
Jeśli używasz maszynopisu, operator rozkładania, jak pokazano, jest kompilowany w celu Math.max.apply(Math, arr)zapewnienia zgodności z „maksymalnym”.
Simon_Weaver
1
Także z MDN: „zarówno rozprzestrzenianie się, jak (...)i applyniepowodzenie lub zwrócenie niewłaściwego wyniku, jeśli tablica zawiera zbyt wiele elementów [...] Rozwiązanie redukujące nie ma tego problemu” Testowanie Chrome, FF, Edge i IE11 wydaje się, że jest ok dla tablicy do 100k wartości. (Testowane na Win10 i najnowszych przeglądarkach: Chrome 110k, Firefox 300k, Edge 400k, IE11 150k).
oriadam
To bardzo powolna metoda, co jeśli tablica miałaby tysiące elementów?
Slava Fomin II
@SlavaFominII Rozszerzyłem odpowiedź, aby obejmowała tablice zawierające tysiące elementów.
totymedli
68

Jeśli masz paranoję na punkcie używania Math.max.apply(co może powodować błędy przy podawaniu dużych tablic zgodnie z MDN ), spróbuj tego:

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

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

Funkcje anonimowe są niestety konieczne (zamiast używać, Math.max.bind(Math)ponieważ reducenie tylko przekazują ai bdo jej funkcji, ale także ii odniesienia do samej tablicy, więc musimy upewnić się, że nie próbujemy też wywoływać maxtych funkcji).

Daniel Buckmaster
źródło
W twoim przykładzie ES6 jest jakiś powód, dla którego po prostu nie powrócisz Math.max(...array)?
Wojciech Bednarski
@WojciechBednarski ta strona wydaje się sugerować, że użycie operatora rozkładania jest tym samym, co przekazywanie tablicy apply, i dlatego ma takie same wady (maksymalny limit argumentów).
Daniel Buckmaster
Dzięki za to. Po prostu możesz poprawić brakujący nawias po zmniejszeniu:function arrayMax(array) { return array.reduce(function(a, b) { return Math.max(a, b); }); // <--------- missing ) }
Arkowsky
1
@DanielDietrich Wydaje mi się, że zrobienie ekwiwalentu, wywołanie Math.min()bez wartości, zwraca Infinity, więc te funkcje mogłyby zostać użyte reduce(..., Infinity)do dopasowania tego zachowania. Wolę jednak, aby generował wyjątek (jak ma to miejsce obecnie), ponieważ przyjmowanie minimum pustej tablicy wydaje się być błędem.
Daniel Buckmaster
1
jak dotąd redukcja jest najwolniejsza.
Алексей Лещук
40

.apply jest często używany, gdy celem jest wywołanie funkcji variadic z listą wartości argumentów, np

Math.max([value1[,value2, ...]])Zwraca największą zero lub więcej cyfr.

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

Ta Math.max()metoda nie pozwala przekazać w tablicy. Jeśli masz listę wartości, które musisz uzyskać największą, zwykle wywoływałbyś tę funkcję za pomocą Function.prototype.apply () , np.

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

Jednak od ECMAScript 6 można używać operatora rozkładania :

Operator rozkładania pozwala na rozwinięcie wyrażenia w miejscach, w których oczekuje się wielu argumentów (dla wywołań funkcji) lub wielu elementów (dla literałów tablicowych).

Za pomocą operatora rozkładania powyższe można przepisać jako takie:

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

Podczas wywoływania funkcji za pomocą operatora variadic można nawet dodać dodatkowe wartości, np

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

Premia:

Operator spread umożliwia użycie składni dosłownego tablicy do tworzenia nowych tablic w sytuacjach, gdy w ES5 trzeba by spaść z powrotem do kodu imperatyw, używając kombinacji push, spliceitp

let foo = ['b', 'c'];
let bar = ['a', ...foo, 'd', 'e']; // ['a', 'b', 'c', 'd', 'e']
Gajus
źródło
1
Twój ostatni przykład premii zostałby napisany przy użyciu concatwiększości programistów, ponieważ pozwala zachować pojedynczy styl linii.
Cody Allan Taylor
31

Dwa sposoby są krótsze i łatwiejsze:

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

Sposób 1 :

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

Sposób 2 :

let max = arr.reduce(function(a, b) {
    return Math.max(a, b);
});
Hafizur Rahman
źródło
Uważaj, jeśli tablica jest pusta - otrzymasz ujemną nieskończoność, która może nie być tym, czego chcesz. Jeśli wolisz 0, możesz użyć [0].concat(arr)lub ze składnią rozprzestrzeniania [0, ...arr](zamiast „arr”)
Simon_Weaver
22

Robisz to poprzez rozszerzenie typu Array:

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

Wzmocniony stąd (autor: John Resig)

inkedmn
źródło
20

Prostym rozwiązaniem w celu znalezienia minimalnej wartości nad jednym Arrayz elementów jest użycie Arrayfunkcji prototypowej reduce:

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

lub za pomocą wbudowanej w JavaScript funkcji Math.Min () (dzięki @Tenflex):

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

Spowoduje minto ustawienie A[0], a następnie sprawdzenie, A[1]...A[n]czy wartość jest ściśle mniejsza niż bieżąca min. Jeśli A[i] < minnastępnie minjest zaktualizowany do A[i]. Po przetworzeniu wszystkich elementów tablicy minjest zwracany jako wynik.

EDYCJA : Uwzględnij pozycję o minimalnej wartości:

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
źródło
3
A. redukcja ((min, val) => Math.min (min, val), A [0]); jeszcze krótszy
Tenflex
Jako pytanie dodatkowe, jak zwrócić nie tylko minwartość, ale także jej pozycję w tablicy?
stevek
@meshfields - Zaktualizowałem odpowiedź.
Nicolas Lykke Iversen,
15

Inni podali już pewne rozwiązania, w których się rozszerzają Array.prototype. Chcę tylko w tej odpowiedzi wyjaśnić, czy powinna być, Math.min.apply( Math, array )czy też Math.min.apply( null, array ). Więc w jakim kontekście należy użyć Mathlub null?

W przypadku przekazania nulljako kontekstu applykontekstem domyślnym jest obiekt globalny ( windowobiekt w przypadku przeglądarek). Podanie Mathobiektu jako kontekstu byłoby właściwym rozwiązaniem, ale nie zaszkodzi to również podaniu null. Oto przykład, kiedy nullmoże powodować problemy podczas dekorowania Math.maxfunkcji:

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

Powyższe spowoduje zgłoszenie wyjątku, ponieważ this.foozostanie ocenione jako window.foo, co jest undefined. Jeśli zastąpimy nullz Mathrzeczy będzie działać zgodnie z oczekiwaniami, a łańcuch „foo” będzie wyświetlane na ekranie (I przetestowane przy użyciu Mozilla Rhino ).

Można prawie założyć, że nikt nie udekorował, Math.maxwięc przejście nullbędzie działać bez problemów.

Ionuț G. Stan
źródło
2
Punkt wzięty. Dlaczego jednak ktoś miałby dekorować Foo.staticMethodi odwoływać się this? Czy nie byłby to błąd w projekcie dekoratora? (chyba że oczywiście chcą się odwołać zasięg globalny, i chce pozostać niezależny od silnika JavaScript jest używany, np Rhino).
Roatin Marth
1
Specyfikacja wyraźnie określa, które określone funkcje powinny odnosić się do „ tej wartości” (w rzeczywistości wyrażenie to pojawia się 125 razy w specyfikacji). Math.max, zaimplementowane zgodnie ze specyfikacją, nie używa this. Jeśli ktoś nadpisuje Math.maxtakie, że używa this, oznacza to, że jego zachowanie narusza specyfikację i należy rzucać w nie ostrymi przedmiotami. Nie powinieneś kodować wokół tej możliwości bardziej niż kodowałbyś wokół możliwości, że ktoś zamienił się Math.maxi Math.minna lulz.
Mark Amery
15

Jeszcze jeden sposób, aby to zrobić:

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

Stosowanie:

var max = arrayMax([2, 5, 1]);
sbr
źródło
Czy ktoś może wyjaśnić, jak to działa? To niezły narkotyk. Czy rozumiem poprawnie: arrayMax jest funkcją i wiążemy coś z właściwością jej prototypu? Co to ma zastosowanie. Wiąże i czy ma go każdy prototyp?
Sam
14

Alternatywne metody


Math.minI Math.maxmetody są obie operacje rekurencyjne, które są dodawane do wywołania stosu silnika JS, a najprawdopodobniej krach na tablicy, która zawiera dużą liczbę elementów
(więcej niż ~ 10⁷ przedmioty, zależy od przeglądarki użytkownika).

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

Uncaught RangeError: Przekroczono maksymalny rozmiar stosu wywołań

Zamiast tego użyj czegoś takiego:

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

Lub z lepszym czasem działania:

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

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

Lub uzyskać zarówno Min i 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] });
}

Lub z jeszcze lepszym czasem pracy *:

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

* Testowany z 1 000 000 elementów:
Dla porównania, czas działania pierwszej funkcji (na mojej maszynie) wyniósł 15,84 ms w porównaniu z drugą funkcją tylko 4,32 ms.

Lior Elrom
źródło
13

Może to pasować do twoich celów.

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
źródło
powinieneś zainicjować swoje v za pomocą „this [0]”, jeśli żadna liczba nie jest mniejsza niż 0
jasonmw
Czy comparernależy wywoływać w określonym zakresie? Ponieważ jak to jest odniesienia, this[index]które są undefinedza każdym razem.
Roatin Marth
Naprawiono, zawsze zapominam o określaniu zakresu funkcji.
ChaosPandion
Aha, teraz @Ionut G. Stan skrytykuje cię za ten sam argument „niewłaściwego kontekstu” jak on, ponieważ twój domyślny Math.xxx
moduł porównujący
To może być prawda, ale nowa sygnatura funkcji nie wymaga zasięgu, ponieważ wymaga 2 obiektów, które należy porównać.
ChaosPandion
12

Dziwi mnie, że nikt nie wspomniał o funkcji redukcji.

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]
Ogier
źródło
Uwaga
1
Nie mogę tego użyć w obecnej wersji Chromium.
PJSCopeland
9

Dla dużych tablic (~ 10⁷ elementów) Math.miniMath.max wywołuje błąd RangeError (przekroczony maksymalny rozmiar stosu wywołań) w node.js.

W przypadku dużych tablic szybkim i brudnym rozwiązaniem jest:

Array.prototype.min = function() {
    var r = this[0];
    this.forEach(function(v,i,a){if (v<r) r=v;});
    return r;
};
Piotr
źródło
8

Miałem ten sam problem, musiałem uzyskać minimalne i maksymalne wartości tablicy i, ku mojemu zaskoczeniu, nie było wbudowanych funkcji tablic. Po długim czytaniu postanowiłem sam przetestować „najlepsze 3” rozwiązania:

  1. rozwiązanie dyskretne: pętla FOR, która sprawdza każdy element tablicy w stosunku do bieżącej wartości maksymalnej i / lub minimalnej;
  2. ZASTOSUJ rozwiązanie: wysyłanie tablicy do wewnętrznych funkcji Math.max i / lub Math.min przy użyciu Apply (null, tablica);
  3. ZMNIEJSZYJ rozwiązanie: ponowne sprawdzanie każdego elementu tablicy za pomocą funkcji zmniejszania (funkcji).

Kod testowy był następujący:

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

Tablica A została wypełniona 100 000 losowych liczb całkowitych, każda funkcja była wykonywana 10 000 razy w Mozilla Firefox 28.0 na komputerze Intel Pentium 4 2,99 GHz z systemem Windows Vista. Czasy podano w sekundach, pobierane przez funkcję performance.now (). Wyniki były następujące, z 3 cyframi ułamkowymi i odchyleniem standardowym:

  1. Rozwiązanie dyskretne: średnia = 0,161 s, sd = 0,078
  2. ZASTOSUJ rozwiązanie: średnia = 3,571 s, sd = 0,487
  3. ZREDUKUJ rozwiązanie: średnia = 0,350 s, sd = 0,044

Rozwiązanie REDUCE było 117% wolniejsze niż rozwiązanie dyskretne. Rozwiązanie APPLY było gorsze, o 2118% wolniejsze niż rozwiązanie dyskretne. Poza tym, jak zauważył Peter, nie działa w przypadku dużych tablic (około 1 000 000 elementów).

Ponadto, aby ukończyć testy, przetestowałem ten rozszerzony dyskretny kod:

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

Czas: średnia = 0,218s, sd = 0,094

Jest więc o 35% wolniejszy niż proste rozwiązanie dyskretne, ale pobiera zarówno wartości maksymalne, jak i minimalne naraz (każde inne rozwiązanie wymagałoby co najmniej dwukrotności tego, aby je odzyskać). Gdy OP potrzebowałby obu wartości, rozwiązaniem dyskretnym byłby najlepszy wybór (nawet jako dwie osobne funkcje, jedna do obliczania maksimum, a druga do obliczania minimum, przewyższałyby drugie najlepsze rozwiązanie ZREDUKUJ).

Cyberknight
źródło
8

Możesz użyć następującej funkcji w dowolnym miejscu w swoim projekcie:

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

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

Następnie możesz wywołać funkcje przekazujące tablicę:

var myArray = [1,2,3,4,5,6,7];
var maximo = getMax(myArray); //return the highest number
Max Cabrera
źródło
8

Poniższy kod działa dla mnie:

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
źródło
7

Iteruj, śledząc cały czas.

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

Spowoduje to pozostawienie wartości min / max null, jeśli w tablicy nie ma żadnych elementów. Ustawi min i max w jednym przejściu, jeśli tablica zawiera jakieś elementy.

Możesz także rozszerzyć tablicę za pomocą rangemetody wykorzystującej powyższe, aby umożliwić ponowne użycie i poprawić czytelność. Zobacz działające skrzypce na 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 }
};

Użyty jako

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

var range = arr.range();

console.log(range.min);
console.log(range.max);
tvanfosson
źródło
@JordanDillonChapian Zgadzam się, ale byłoby trywialne rozszerzenie tej rangefunkcji na funkcję, która byłaby najlepszym sposobem na uzyskanie zarówno minimalnej, jak i maksymalnej wartości w tym samym czasie IMO - tak jak zrobiłem z aktualizacją mojej odpowiedzi.
tvanfosson
6

Myślałem, że podzielę się moim prostym i łatwym do zrozumienia rozwiązaniem.

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

A dla maksimum:

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

Iula Necula
źródło
Dzięki. Zmieniłem odpowiedź.
Ionut Necula
Iteracja jest nadal niepoprawna (dostęp do nieistniejących właściwości).
Bergi,
Co jest nie tak, nie widzę nic złego. Czy możesz podać przykład?
Ionut Necula
1
Teraz odpowiednio zmodyfikowane. Mam nadzieję, że dobrze cię zrozumiałem.
Ionut Necula
6

Oprócz korzystania z funkcji matematycznych max i min, inną funkcją do użycia jest wbudowana funkcja sort (): proszę bardzo

const nums = [12, 67, 58, 30].sort((x, y) => 
x -  y)
let max = nums[0]
let min = nums[nums.length -1]
Pedro JR
źródło
5

Proste rzeczy, naprawdę.

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
źródło
5

Oto jeden ze sposobów uzyskania maksymalnej wartości z tablicy obiektów. Utwórz kopię (z plasterkiem), a następnie posortuj kopię w porządku malejącym i chwyć pierwszy 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
źródło
5

Za pomocą Math.max()lubMath.min()

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

Poniższa funkcja służy Function.prototype.apply()do znalezienia maksymalnego elementu w tablicy numerycznej. getMaxOfArray([1, 2, 3])jest równoważne Math.max(1, 2, 3), ale można używać getMaxOfArray()na programowo skonstruowanych tablicach o dowolnym rozmiarze.

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

Lub dzięki nowemu operatorowi rozkładania uzyskanie maksimum tablicy staje się znacznie łatwiejsze.

var arr = [1, 2, 3];
var max = Math.max(...arr); // 3
var min = Math.min(...arr); // 1
Shilovk
źródło
4

Rozwiązanie ChaosPandion działa, jeśli używasz protoype. Jeśli nie, rozważ to:

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

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

Powyższe zwróci NaN, jeśli wartość tablicy nie jest liczbą całkowitą, dlatego należy zbudować pewną funkcjonalność, aby tego uniknąć. W przeciwnym razie to zadziała.

sójka
źródło
jeerose, dlaczego masz (Matematyka, to) jako narzędzie, gdy Roatin Marth ma tylko (zero, to)?
HankH
@HankH: zobacz moją odpowiedź na Twój komentarz w komentarzu do mojej własnej odpowiedzi.
Roatin Marth
1
Nie rozumiem, co masz na myśli przez „Rozwiązanie ChaosPandion działa, jeśli używasz protoype”. Czym różni się twoje rozwiązanie, z wyjątkiem tego, że używasz Mathobiektu jako kontekstu?
Ionuț G. Stan
Przepraszam, miałem na myśli, że jeśli rozszerzysz prototyp, twój będzie działał. Przeprosiny.
Jay
Więc co jest lepsze, jeeroza czy ChaosPandion?
HankH
3

Jeśli korzystasz z biblioteki sugar.js , możesz pisać arr.min () i arr.max (), jak sugerujesz. Można także uzyskać wartości minimalne i maksymalne z tablic nienumerycznych.

min (map, all = false) Zwraca element w tablicy o najniższej wartości. map może być funkcją mapującą wartość do sprawdzenia lub ciąg znaków działający jako skrót. Jeśli wszystko jest prawdziwe, zwróci wszystkie wartości min w tablicy.

max (map, all = false) Zwraca element w tablicy o największej wartości. map może być funkcją mapującą wartość do sprawdzenia lub ciąg znaków działający jako skrót. Jeśli wszystko jest prawdziwe, zwróci wszystkie maksymalne wartości w tablicy.

Przykłady:

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

Biblioteki takie jak Lo-Dash i underscore.js zapewniają również podobne zaawansowane funkcje min i max:

Przykład z 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
źródło
3
let arr = [2,5,3,5,6,7,1];

let max = Math.max(...arr); // 7
let min = Math.min(...arr); // 1
UA_
źródło
2
To rozwiązanie zostało już dostarczone przez wielu innych osób odpowiadających na to pytanie. Co dodaje twoja odpowiedź?
Nick
3

Próbować

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

Dla Math.min / max (+ Apply) otrzymujemy błąd:

Przekroczono maksymalny rozmiar stosu wywołań (Chrome 74.0.3729.131)

Kamil Kiełczewski
źródło