Найти минимальный / максимальный элемент массива в JavaScript


779

Как я могу легко получить минимальный или максимальный элемент массива 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 .
Тотимедли

1
Попробуйте пометить ответ как принятый.
Алекс

вот эталон для сравнения скорости наиболее распространенных способов сделать это: jsben.ch/#/1QuTg
EscapeNetscape

ES6 в основном великолепно! :)
datdinhquoc

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

Ответы:


828

Как насчет увеличения встроенного объекта 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подключиться 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внутреннюю.
Роатин Март

31
Как программист C # мне нужны строго типизированные вопросы.
ChaosPandion

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

11
Я понизил голос, потому что предложенный подход потребляет O (n) памяти в кадре стека, и в результате вылетает на больших массивах. В моем случае только 130000 номеров было достаточно для сбоя nodejs.
Алексей Тимановский

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...», но, похоже, мне не нужно это делать (устанавливая первый аргумент applyas null).
Цзыюан

9
@ziyuang Когда вы называете это как Math.max(a,b), Mathпередается как thisзначение, поэтому имеет смысл сделать то же самое при вызове с apply. Но Math.maxне использует thisзначение, поэтому вы можете передать любое значение, которое вы хотите.
Oriol

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решение является самым медленным. Даже если вы работаете с массивом, содержащим миллионы элементов, лучше использовать стандартный цикл for . Смотрите мой ответ для более.
Тотимедли

152

Использование оператора распространения (ES6)

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


8
Это решение уже было предоставлено несколькими другими ответами.
Тотимедли

15
Math.max (... []) = -Infinity. хахаха 😂😂😂
Дэвид

@DavidPortabella не уверен, почему это смешно. Вот как это работает в соответствии со спецификацией :If no arguments are given, the result is -∞.
Патрик Робертс

3
да, я имел в виду, что спецификация javascript ужасна. Кажется очевидным, что минимальное число не может быть вычислено. В других более серьезных языках программирования, таких как Scala, запрос минимума пустого массива вызывает исключение.
Дэвид Портабелла

3
Scala для людей, которым нужна машина, чтобы сказать им, что они сделали это неправильно
thedanotto

107

ТЛ; др

// 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 это означает, что когда дело доходит до нахождения минимума / максимума с использованием 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 году результаты показывают, что стандартный цикл (который, кстати, не имеет ограничения по размеру) является самым быстрым во всем мире. applyи распространение идет за ним, затем гораздо позже гибридное решение MDN, то reduceсамое медленное.

Почти все тесты дали одинаковые результаты, за исключением одного, где спред почему-то оказался самым медленным.

Если вы увеличите свой массив до 1 миллиона элементов, все начнет ломаться, и вы останетесь со стандартным циклом в качестве быстрого решения и reduce более медленного.

Тест JSPerf

Результаты тестов jsperf.com для различных решений, чтобы найти минимальный / максимальный элемент массива

Тест JSBen

Результаты тестов jsben.com для различных решений, чтобы найти минимальный / максимальный элемент массива

Тест JSBench.me

Результаты тестов jsbench.me для различных решений по нахождению минимального / максимального элемента массива

Исходный код теста


Если вы используете машинописный текст, оператор распространения, как показано, скомпилирован Math.max.apply(Math, arr)для максимальной совместимости.
Simon_Weaver

1
Также из MDN: «оба распространяются (...)и applyбудут либо давать сбой, либо возвращать неправильный результат, если в массиве слишком много элементов [...] Решение для сокращения не имеет этой проблемы». При тестировании Chrome, FF, Edge и IE11 кажется, что это хорошо для массива до 100 тыс. значений. (Проверено на Win10 и последних браузерах: Chrome 110k, Firefox 300k, Edge 400k, IE11 150k).
Ориадам

Это очень медленный метод, что если массив будет иметь тысячи элементов?
Слава Фомин II

@SlavaFominII Я расширил ответ, чтобы он охватывал массивы с тысячами элементов.
Тотимедли

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

Есть ли способ исключить нулевые значения в способе 1?
bonbon.langes

22

Вы делаете это путем расширения типа Array:

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

Усиленный отсюда (Джон Резиг)


20

Простое решение для нахождения минимального значения над Arrayэлементом состоит в использовании Arrayфункции prototype 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возвращается как результат.

РЕДАКТИРОВАТЬ : Включить позицию минимального значения:

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вернуть не только значение, но и его положение в массиве?
Stevek

@meshfields - я обновил ответ.
Николя Ликке Иверсен

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).
Роатин Март

1
В спецификации явно указано, какие функции должны ссылаться на « значение this » (действительно, эта фраза встречается в спецификации 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 - это функция, и мы связываем что-то со свойством ее прототипа? Что это за apply.bind и есть ли у каждого прототипа?
Сэм

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

14

Альтернативные Методы


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

Math.max (... Массив () 1000000 .keys ());

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

Или чтобы получить и Мин и Макс:

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 элементов:
просто для справки, время выполнения первой функции (на моей машине) составило 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всегда.
Роатин Март

Исправлено, я всегда забываю об определении уровня функции.
ChaosPandion

А теперь, теперь @Ionut G. Stan будет критиковать вас за тот же аргумент «неправильного контекста», что и он мне, поскольку ваш defaultr Comparer ( Math.xxx) будет работать в глобальной области видимости ...
Роатин Март,

Это может быть правдой, но новая сигнатура функции не требует области видимости, поскольку она берет 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.
ПАОПеленд

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: повторная проверка каждого элемента массива с использованием метода limit (function).

Тестовый код был таким:

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,161 с, сд = 0,078
  2. Применить решение: среднее = 3,571 с, SD = 0,487
  3. СНИЖЕНИЕ решения: среднее = 0,350 с, SD = 0,044

Раствор REDUCE был на 117% медленнее, чем дискретный раствор. Раствор APPLY оказался хуже, на 2118% медленнее, чем дискретный раствор. Кроме того, как заметил Питер, он не работает для больших массивов (около 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,218 с, сд = 0,094

Таким образом, он на 35% медленнее, чем простое дискретное решение, но одновременно извлекает как максимальные, так и минимальные значения (для их извлечения любому другому решению потребуется как минимум вдвое больше). Как только ОП потребуются оба значения, дискретное решение будет лучшим выбором (даже если две отдельные функции, одна для расчета максимума, а другая для вычисления минимума, они превзойдут второе лучшее, решение REDUCE).


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 за один проход, если в массиве есть какие-либо элементы.

Вы также можете расширить 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функции, которая была бы лучшим способом получить как минимальное, так и максимальное значение IMO одновременно - как я сделал с обновлением своего ответа.
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);



Спасибо. Я изменил свой ответ.
Ionut Necula

Итерация все еще неверна (доступ к несуществующим свойствам).
Берги

Что не так, я не вижу ничего плохого. Можете ли вы привести пример, пожалуйста?
Ионут Некула

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

5

Помимо использования математической функции max и min, еще одна функция - встроенная функция sort (): здесь мы идем

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

4

Решение ChaosPandion работает, если вы используете прототип. Если нет, подумайте об этом:

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

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

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


Господи, почему у вас (Математика, это) в качестве agruments, когда Roatin Marth только имеет (ноль, это)?
HankH

@HankH: см. Мой ответ на ваш комментарий в комментарии к моему собственному ответу.
Роатин Март

1
Я не понимаю, что вы подразумеваете под «решением ChaosPandion, если вы используете прототип». Чем отличается ваше решение, кроме того, что вы используете Mathобъект в качестве контекста?
Ionuț G. Stan

Извините, я имел в виду, если вы продлите прототип, ваш будет работать. Извиняюсь.
сойка

Так что же лучше, шутка или ChaosPandion's?
HankH

3

Если вы используете библиотеку sugar.js , вы можете написать arr.min () и arr.max (), как вы предлагаете. Вы также можете получить минимальное и максимальное значения из нечисловых массивов.

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

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 (+ apply) мы получаем ошибку:

Превышен максимальный размер стека вызовов (Chrome 74.0.3729.131)

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.