Знайдіть елемент min / max масиву в JavaScript


778

Як я можу легко отримати елемент min або max з масиву JavaScript?

Приклад Psuedocode:

let array = [100, 0, 50]

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

93
Примітка: З ECMAScript 6 ви можете використовувати новий спред оператор (три точки: ...) з Math.max()так: Math.max(...[2, 5, 16, 1]). Дивіться мою відповідь з документації MDN .
totymedli

1
Розгляньте позначення відповіді прийнятою.
Олексій

тут орієнтир для порівняння швидкості найбільш поширених способів це зробити: jsben.ch/#/1QuTg
EscapeNetscape

es6 в основному чудовий! :)
datdinhquoc

Без ES6 Math.max.apply(null, [2,5,16,1])
Томер

Відповіді:


827

Як щодо розширення вбудованого об’єкта Array для використання Math.max/ Math.minзамість:

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

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

Ось JSFiddle .

Доповнюючи вбудовані модулі можуть привести до сутичок з іншими бібліотеками (деякі бачать), так що ви можете бути більш комфортно з просто apply«ING Math.xxx()в масив безпосередньо:

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

Крім того, якщо ваш браузер підтримує ECMAScript 6, ви можете використовувати оператор розповсюдження, який функціонує аналогічно applyметоду:

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

8
@HankH: передача nullабо, Mathабо {}будь-що, apply()або call()не має жодного стосунку до результату. Math.maxне має і не має посилатися thisвнутрішньо.
Roatin Marth

31
Як програміст на C # мені потрібні чітко набрані запитання.
ChaosPandion

7
Просто поділившись помилкою jQuery, яку я робив із кодом, над котрим мені знадобилося тривалий час. Масив jquery добре працює на всіх, крім iPad. Мені довелося перетворити масив у справжній власний масив, щоб він працював. З певних причин постраждав лише від одного пристроюMath.max.apply(null, $.makeArray(array));
Forrest

11
Я підкреслив, тому що запропонований підхід споживає O (n) пам'яті у фреймі стека, і в результаті виходить з ладу на великих масивах. У моєму випадку всього лише 130000 номерів було достатньо для збою вузлів.
Олексій Тимановський

14
Не збільшуйте подібні вбудовані прототипи. Йдеться не лише про конфлікти з іншими бібліотеками; йдеться також про потенціал, який надає сам браузер .maxабо .minметод у майбутньому. Ідеально реалістичний сценарій: Ви використовуєте цю відповідь. У 2016 році специфікації ES7 або ES8 Array.maxта Array.min. На відміну від цієї версії, вони працюють на струнах. Ваш майбутній колега намагається отримати алфавітно-останню рядок у масиві за допомогою вже добре задокументованого нативного .max()методу, але загадково отримує NaN. Години пізніше вона знаходить цей код, запускає git blameі проклинає ваше ім’я.
Марк Амері

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

Повне обговорення див: http://aaroncrane.co.uk/2008/11/javascript_max_api/


13
У чому різниця між Math.max.apply(Math, array)і Math.max.apply(null, array)? У блозі йдеться про те, що "... вам також доведеться зайвий раз сказати, що maxналежить Math...", але, здається, мені не доведеться цього робити (встановивши перший аргумент applyяк null).
ziyuang

9
@ziyuang Коли ви називаєте це так Math.max(a,b), Mathпередається як thisзначення, тому може бути доцільним те саме робити під час дзвінка зі apply. Але Math.maxне використовує thisзначення, тому ви можете передавати будь-яке значення, яке вам потрібно.
Оріол

199

Для великих масивів (~ 10⁷ елементів), Math.minі Math.maxобидва створюють наступну помилку в Node.js.

RangeError: Максимальний розмір стека викликів перевищено

Більш надійним рішенням є не додавати кожен елемент до стеку викликів, а замість цього передавати масив:

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

Якщо вас турбує швидкість, наступний код ~ в 3 рази швидший, ніж Math.max.applyна моєму комп’ютері. Дивіться 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;
};

Якщо ваші масиви містять рядки замість чисел, вам також потрібно примусити їх до чисел. Наведений нижче код робить це, але він уповільнює код ~ 10 разів на моїй машині. Дивіться 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;
};

призначити minта maxостанньому елементу та зменшити ітерації на 1 ( while(--len));)
Venugopal

@ Venugopal тоді вам потрібна спеціальна перевірка, щоб побачити, чи масив порожній і повернути +/- Infinity
Linus Unnebäck

2
Дивно ... Я зайшов на пов’язаний веб-сайт ... і протестувавши в Firefox 51.0.0 / Mac OS X 10.12.0, підхід на основі зменшення на 30% повільніше, ніж на основі циклу ... зовсім інші результати
Pierpaolo Cira

2
very different results ви зробили це через 5 років)
Алексей Лещук

1
У 2019 році reduceрішення є найповільнішим. Навіть якщо ви працюєте з масивом, який містить мільйони елементів, краще використовувати стандарт для циклу . Дивіться мою відповідь для більш детального.
totymedli

152

Використання оператора розвороту (ES6)

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


8
Це рішення було надано безліччю інших відповідей.
totymedli

15
Math.max (... []) = -Нескінченність. хахаха 😂😂😂
Девід Портабелла

@DavidPortabella не впевнений, чому це смішно. Ось як це працює відповідно до специфікації :If no arguments are given, the result is -∞.
Патрік Робертс

3
так, я мав на увазі, що специфікація javascript жахлива. Здається очевидним, що мінус жодних чисел неможливо обчислити. В інших більш серйозних мовах програмування, таких як Scala, запит на хвилину порожнього масиву викидає виняток.
Девід Портабелла

3
Scala призначений для людей, яким потрібна машина, щоб сказати їм, що вони зробили не так
thedanotto

106

тл; д-р

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

В офіційному MDN документи наMath.max() вже охоплюють це питання:

Наступна функція використовує Function.prototype.apply () для пошуку максимального елемента в числовому масиві. getMaxOfArray([1, 2, 3])еквівалентно Math.max(1, 2, 3), але ви можете використовувати getMaxOfArray()на програмно побудованих масивах будь-якого розміру.

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

Або з новим оператором розповсюдження отримати максимум масиву стає набагато простіше.

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

Максимальний розмір масиву

Згідно з MDN, рішення applyі розповсюдження мали обмеження 65536, що виходило з межі максимальної кількості аргументів:

Але будьте обережні: використовуючи такий спосіб застосування, ви ризикуєте перевищити ліміт довжини аргументів двигуна JavaScript. Наслідки застосування функції із занадто великою кількістю аргументів (думаю, що це більше десятків тисяч аргументів) різняться між двигунами ( JavaScriptCore має жорстко обмежений аргумент 65536 ), оскільки обмеження (дійсно навіть характер будь-якого надмірно великого стека поведінка) не визначено. Деякі двигуни викинуть виняток. Більш згубно, інші будуть довільно обмежувати кількість аргументів, фактично переданих застосованій функції. Щоб проілюструвати цей останній випадок: якщо такий двигун мав обмеження в чотири аргументи (фактичні обмеження, звичайно, значно вищі), було б так, якби аргументи 5, 6, 2, 3 були передані для застосування у наведених вище прикладах, а не повний масив.

Вони навіть забезпечують гібридне рішення, яке насправді не має хороших показників порівняно з іншими рішеннями. Дивіться тест на працездатність нижче для отримання додаткової інформації.

У 2019 році фактичний ліміт - максимальний розмір стека викликів . Для сучасних настільних браузерів на базі Chromium це означає, що якщо мова йде про знаходження min / max за допомогою applyабо розповсюдження, практично максимальний розмір для масивів лише чисел становить ~ 120000 . Над цим буде переповнюватися стек, і буде викинута наступна помилка:

RangeError: Максимальний розмір стека викликів перевищено

За допомогою наведеного нижче сценарію (на основі цієї публікації в блозі ), скориставшись цією помилкою, ви можете обчислити ліміт для вашого конкретного середовища.

Увага! Запуск цього сценарію потребує часу, і залежно від продуктивності вашої системи це може сповільнити або вийти з ладу ваш браузер / систему!

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

Продуктивність на великих масивах

На основі тесту в коментарі EscapeNetscape я створив деякі орієнтири, які тестують 5 різних методів на масив, що містить випадкове число, лише з 100000 елементів .

У 2019 році результати показують, що стандартний цикл (у якого BTW не має обмеження розміру) є найшвидшим скрізь. applyі розповсюдження приходить тісно після нього, то набагато пізніше гібридне рішення MDN, reduceяк найповільніше.

Практично всі тести дали однакові результати, за винятком тих, де поширення, чомусь, виявилося найповільнішим.

Якщо ви збільшите масив, щоб отримати 1 мільйон елементів, все починає ламатися, і вам залишається стандартний цикл як швидке рішення, так і reduceповільніше.

Орієнтир JSPerf

Результати еталонів jsperf.com для різних рішень для пошуку елемента min / max масиву

Орієнтир JSBen

Результати порівняння jsben.com для різних рішень для пошуку елемента min / max масиву

Орієнтир JSBench.me

Результати еталону jsbench.me для різних рішень для пошуку елемента min / max масиву

Вихідний код орієнтиру


Якщо ви використовуєте машинопис, оператор розповсюдження, як показано, складається Math.max.apply(Math, arr)для сумісності "max".
Simon_Weaver

1
Також від MDN: "і розповсюдження, (...)і applyбуде або збій, або поверне неправильний результат, якщо в масиві є занадто багато елементів [...] У рішення для зменшення проблеми не виникає" Тестування Chrome, FF, Edge та IE11 здається, що це ОК для масиву до 100k значень. (Тестовано на Win10 та найновіших браузерах: Chrome 110k, Firefox 300k, Edge 400k, IE11 150k).
oriadam

Це дуже повільний метод, що робити, якщо масив матиме тисячі елементів?
Слава Фомін II

@SlavaFominII Я розширив відповідь, щоб вона охоплювала масиви з тисячами елементів.
totymedli

68

Якщо ви користуєтеся параноїком, як я, щодо використання Math.max.apply(що може спричинити помилки при наданні великих масивів відповідно до MDN ), спробуйте це:

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

Або в 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));
}

Анонімні функції, на жаль, необхідні (замість того, щоб використовувати, Math.max.bind(Math)оскільки reduceце не просто передає aі bйого функції, але також iі посилання на сам масив, тому ми повинні переконатися, що ми також не намагатимемося закликати maxдо них.


Ваш приклад ES6, чи є якась причина, чому не просто повернутися Math.max(...array)?
Войцех Беднарський

@WojciechBednarski на цій сторінці, здається, напрошується думка, що використовувати оператор розширення - це те саме, що передавати масив до apply, і тому має ті самі недоліки (максимальний ліміт аргументів).
Даніель Бакмастер

Дякую за це Тільки ви можете виправити відсутні дужки після зменшення:function arrayMax(array) { return array.reduce(function(a, b) { return Math.max(a, b); }); // <--------- missing ) }
Арковський

1
@DanielDietrich Я думаю, що еквівалент, виклик Math.min()без значень, повертається Infinity, тому ці функції можна використовувати reduce(..., Infinity)для відповідності цій поведінці. Я вважаю за краще викинути виняток, хоча (як це робиться в даний час), тому що взяти мінімум порожнього масиву, мабуть, буде помилкою.
Даніель Бакмастер

1
поки що зниження є найповільнішим.
Алексей Лещук

40

.apply часто використовується, коли має намір викликати різноманітну функцію зі списком значень аргументів, наприклад

Math.max([value1[,value2, ...]])Функція повертає найбільше з нуля або більше чисел.

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

Math.max()Метод не дозволяє передавати в масиві. Якщо у вас є список значень, для яких вам потрібно отримати найбільше, зазвичай ви викликаєте цю функцію за допомогою Function.prototype.apply () , наприклад

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

Однак, з ECMAScript 6, ви можете використовувати оператор розповсюдження :

Оператор розповсюдження дозволяє розширити вираз у місцях, де очікується багато аргументів (для викликів функцій) або декількох елементів (для літералів масиву).

Використовуючи оператор розповсюдження, вищезазначене можна переписати як таке:

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

Під час виклику функції за допомогою варіаторного оператора ви навіть можете додавати додаткові значення, наприклад

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

Бонус:

Оператор Spread дозволяє використовувати синтаксис литерала масиву для створення нових масивів в ситуаціях , коли в ES5 вам потрібно буде падати назад імперативний код, використовуючи комбінацію push, spliceі т.д.

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

1
Ваш останній приклад в бонусі буде написаний з використанням concatбільшості програмістів, оскільки він дозволяє підтримувати стиль єдиного рядка.
Коді Аллан Тейлор

31

Два способи - коротший і простіший:

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

Спосіб 1 :

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

Спосіб 2 :

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

Слідкуйте, чи масив порожній - ви отримаєте негативну нескінченність, яка може бути не такою, яку ви хочете. Якщо ви хочете отримати, 0ви можете використовувати [0].concat(arr)або з синтаксисом розповсюдження [0, ...arr](замість 'arr')
Simon_Weaver

22

Ви робите це, розширивши тип масиву:

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

Підсилений звідси (Джон Ресіг)


20

Просте рішення для знаходження мінімального значення Arrayдля елемента - використання функції Arrayпрототипу reduce:

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

або за допомогою вбудованої функції JavaScript Math.Min () (спасибі @Tenflex):

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

Це набори minдо A[0], а потім перевіряє , A[1]...A[n]чи є він строго менше , ніж струм min. Якщо A[i] < minпотім minоновлено до A[i]. Коли всі елементи масиву оброблені,min як результат повертається.

EDIT : Включити позицію мінімального значення:

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]); ще коротше
Tenflex

Як бонусне питання, як повернути не тільки minзначення, але і його позицію в масиві?
стевек

@meshfields - я оновив відповідь.
Nicolas Lykke Iversen

15

Інші вже давали деякі рішення, в яких вони збільшуються Array.prototype. Все що я хочу в цій відповіді, щоб з'ясувати , чи повинна вона бути Math.min.apply( Math, array )або Math.min.apply( null, array ). Отже, який контекст слід використовувати, Mathабо null?

При проходженні null як контекст до apply, тоді контекст буде за замовчуванням глобальним об'єктом ( windowоб'єкт у випадку браузерів). Передача Mathоб'єкта як контексту було б правильним рішенням, але це також не зашкодить пройти null. Ось приклад, коли nullможна створити проблеми під час декорування Math.maxфункції:

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

Вищесказане буде винятком, оскільки this.foo буде оцінено як window.foo, що є undefined. Якщо ми замінимо nullз Math, все буде працювати , як очікувалося , а рядок «Foo» буде виведений на екран (я перевірив це з допомогою Mozilla Rhino ).

Можна майже припустити, що ніхто не прикрашав Math.max , проїзд nullбуде працювати без проблем.


2
Точка взята. Однак чому б хтось прикрашав Foo.staticMethodі посилався this? Хіба це не буде помилкою в дизайні декоратора? (якщо, звичайно, вони не хотіли посилатися на глобальну область застосування, і хотіли б залишатися незалежними від використовуваного двигуна JavaScript, наприклад, Rhino).
Roatin Marth

1
Специфікація є чіткою щодо того, які конкретизовані функції повинні посилатися на " це значення" (дійсно, ця фраза відображається 125 разів у специфікації). Math.max, реалізований за специфікацією, не використовується this. Якщо хтось переорієнтовує Math.maxтакий, який він використовує this, то він змусив його поведінку порушити специфікацію, і ви повинні кидати на них гострі предмети. Ви не повинні кодувати таку можливість більше, ніж ви б кодували можливість того, що хтось помінявся Math.maxі Math.minдля lulz.
Марк Амері

15

Ще один спосіб зробити це:

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

Використання:

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

Чи може хтось пояснити, як це працює? Це симпатичний допінг. Чи правильно я розумію: arrayMax - це функція, і ми щось прив'язуємо до властивості її прототипу? Що це за застосувати.bind і чи має кожен прототип це?
Сем,

Ви можете перевірити: benalman.com/news/2012/09/partial-application-in-javascript
sbr

14

Альтернативні методи


Math.minІ Math.maxметоди є рекурсивними операції , які додаються в стек викликів двигуна JS, і , швидше за все , збій на масив , який містить велику кількість елементів
(більш ~ 10⁷ пунктів, залежить від браузера користувача).

Math.max (... масив (1000000). Ключів ());

Uncaught RangeError: Перевищено максимальний розмір стека викликів

Натомість використовуйте щось подібне:

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

Або з кращим часом виконання:

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

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

Або отримати Min і 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] });
}

Або з ще кращим часом роботи *:

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

* Тестовано з 1 000 000 елементів:
Тільки для довідки, час роботи 1-ї функції (на моїй машині) склав 15,84 мс та 2-ю функцію лише 4,32 мс.


13

Це може відповідати вашим цілям.

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

ви повинні ініціалізувати свій v із "this [0]" у випадку, якщо число не менше 0
jasonmw

Чи comparerповинно називатися в якійсь конкретній області застосування? Бо як це посилання, this[index]які єundefined щоразу.
Roatin Marth

Виправлено, я завжди забуваю про оцінку рівня функцій.
ChaosPandion

О, тепер @Ionut G. Stan буде критикувати вас за той же аргумент "неправильного контексту", що і він, як і я, оскільки ваш порівняльний замовчувач (Math.xxx ) буде працювати в глобальному масштабі ...
Roatin Marth

Це може бути правдою, але новий підпис функції не потребує розмаху, оскільки він займає 2 об'єкти, які потрібно порівняти.
ChaosPandion


12

Я здивований, що ніхто не згадує про функцію зниження.

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]

Майте в виду: зменшення () підтримується з IE9, см developer.mozilla.org/en-US/docs/Web/JavaScript/Reference / ...
Paul Gobée

1
Я не можу використовувати це в поточній версії Chromium.
PJSCopeland

9

Для великих масивів (~ 10⁷ елементів) Math.minта Math.maxвиконує пробіг RangeError (Максимальний розмір стека викликів перевищено) у node.js.

Для великих масивів швидке та брудне рішення:

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

8

У мене була така ж проблема, мені потрібно було отримати мінімальне та максимальне значення масиву, і, на моє здивування, для масивів не було вбудованих функцій. Почитавши багато, я вирішив сам випробувати «топ-3» рішення:

  1. дискретне рішення: цикл FOR для перевірки кожного елемента масиву на предмет поточного max та / або min значення;
  2. APPLY рішення: відправлення масиву до внутрішніх функцій Math.max та / або Math.min за допомогою Apply (null, array);
  3. REDUCE рішення: повторення перевірки кожного елемента масиву за допомогою функції скарачення (функція).

Код тесту був таким:

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

Масив A був заповнений 100 000 випадковими цілими числами, кожна функція виконувалася 10 000 разів на Mozilla Firefox 28.0 на робочому столі Intel Pentium 4 2,99 ГГц з Windows Vista. Часи в секундах, отримані функцією performance.now (). Результати були такими, з 3 дробовими цифрами та стандартним відхиленням:

  1. Дискретний розчин: середнє = 0,161s, sd = 0,078
  2. ЗАСТОСУЙТЕ рішення: середнє = 3,571s, sd = 0,487
  3. ЗНИЖЕННЯ рішення: середнє = 0,350s, sd = 0,044

Рішення REDUCE було на 117% повільніше, ніж дискретний розчин. Рішення APPLY було гірше, на 2 218% повільніше, ніж дискретний розчин. Крім того, як зауважив Пітер, він не працює для великих масивів (близько 1 000 000 елементів).

Також для завершення тестів я протестував цей розширений дискретний код:

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

Час: середнє = 0,218s, sd = 0,094

Отже, він на 35% повільніше, ніж простий дискретний розчин, але він отримує одночасно і максимальні, і мінімальні значення (будь-яке інше рішення знадобиться принаймні вдвічі, ніж для їх отримання). Як тільки ОП потребували обох значень, дискретний варіант буде найкращим вибором (навіть якщо дві окремі функції, одна для обчислення максимуму, а інша для обчислення мінімуму, вони перевершать другу кращу, рішення ЗНИЖЕННЯ).


8

Ви можете використовувати таку функцію в будь-якому місці свого проекту:

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

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

І тоді ви можете викликати функції, що передають масив:

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

8

Наступний код працює для мене:

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

Повторіть, простежуючи, як ви йдете.

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

Це залишить min / max null, якщо в масиві немає елементів. Буде встановлено min та max за один прохід, якщо масив має будь-які елементи.

Ви також можете розширити Array rangeметодом, використовуючи вищезазначене, щоб дозволити повторне використання та поліпшення читабельності. Дивіться робочу загадку на веб-сайті 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 }
};

Використовується як

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

var range = arr.range();

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

@JordanDillonChapian Я погоджуюся, але було б тривіально розширити це на rangeфункцію, яка була б найкращим способом отримати одночасно ІМО і максимум - як це я робив із оновленням своєї відповіді.
tvanfosson

6

Я думав, що поділюсь своїм простим і легким для розуміння рішенням.

За хв:

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

І для максимуму:

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



Дякую. Я змінив свою відповідь.
Іонут Некула

Ітерація все ще неправильна (доступ до неіснуючих властивостей).
Бергі

Що не так, я не бачу нічого поганого. Чи можете ви запропонувати приклад, будь ласка?
Іонут Некула

1
Змінено відповідно. Сподіваюся, я вас правильно зрозумів.
Іонут Некула

6

Окрім використання математичних функцій max та min, ще одна функція, яка використовується - це вбудована функція sort (): ось ми і підемо

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

5

Прості речі, справді.

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

Ось один із способів отримати максимальне значення з масиву об’єктів. Створіть копію (з фрагментом), після чого відсортуйте копію у порядку зменшення та візьміть перший елемент.

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

Використання Math.max()абоMath.min()

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

Наступна функція використовує Function.prototype.apply()для пошуку максимального елемента в числовому масиві. getMaxOfArray([1, 2, 3])еквівалентно Math.max(1, 2, 3), але ви можете використовувати getMaxOfArray()на програмно побудованих масивах будь-якого розміру.

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

Або з новим оператором розповсюдження отримати максимум масиву стає набагато простіше.

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

4

Рішення ChaosPandion працює, якщо ви використовуєте прототип. Якщо ні, то врахуйте це:

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

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

Вищенаведене поверне NaN, якщо значення масиву не є цілим числом, тому ви повинні побудувати деяку функціональність, щоб уникнути цього. Інакше це спрацює.


jeerose, чому ти маєш (Math, this) як agruments, коли у Roatin Marth є лише (null, this)?
HankH

@HankH: дивись мою відповідь на твій коментар у коментарі до моєї власної відповіді.
Roatin Marth

1
Я не розумію, що ви маєте на увазі під впливом "рішення ChaosPandion, якщо ви використовуєте прототип". Чим ваше рішення відрізняється, якщо ви не використовуєте Mathоб'єкт як контекст?
Ionuț G. Stan

Вибачте, я мав на увазі, якщо ви продовжите прототип, ваш працюватиме. Вибачення.
Джей

Отже, що краще, євреї або ChaosPandion?
HankH

3

Якщо ви використовуєте бібліотеку sugar.js , ви можете написати arr.min () та arr.max (), як ви запропонуєте. Ви також можете отримати значення min та max з нечислових масивів.

min (map, all = false) Повертає елемент у масиві з найменшим значенням. map може бути функцією, що відображає значення, що перевіряється, або рядок, що виступає в якості ярлика. Якщо все вірно, поверне всі значення min у масиві.

max (map, all = false) Повертає елемент у масиві з найбільшим значенням. map може бути функцією, що відображає значення, що перевіряється, або рядок, що виступає в якості ярлика. Якщо все вірно, поверне всі максимум значень у масив.

Приклади:

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

Бібліотеки, такі як Lo-Dash та underscore.js, також забезпечують подібні потужні функції min та max:

Приклад з 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
Це рішення вже було надано багатьма іншими відповідями на це питання. Що додає ваша відповідь?
Нік

3

Спробуйте

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

Для Math.min / max (+ застосувати) ми отримуємо помилку:

Максимальний розмір стека викликів перевищено (Chrome 74.0.3729.131)

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.