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

Как я могу легко получить минимальный или максимальный элемент массива JavaScript?

Пример Psuedocode:

let array = [100, 0, 50]

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

61 ответ

Простые вещи, правда.

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

Поиск элементов Max и Min массива в JavaScript.

Вы можете использовать несколько подходов:

С использованием Math.min()и Math.max()

      let array = [100, 0, 50];
Math.min(...array); // 0
Math.max(...array); // 100

С использованиемSorting

      let array = [100, 0, 50];
arraySorted = array.toSorted((a, b) => a - b); // [0, 50, 100];
arraySorted.at(0);  // 0
arraySorted.at(-1); // 100

Использование простого цикла for

      let array = [100, 0, 50];
let maxNumber = array[0];
let minNumber = array[0];
for (let i = 1; i < array.length; i++) {
  if (array[i] > maxNumber) {
    maxNumber = array[i];
  }
  if (array[i] < minNumber) {
    minNumber = array[i];
  }
}

Вы можете использовать методы lodash

_.max([4, 2, 8, 6]);
returns => 8

https://lodash.com/docs/4.17.15

_.min([4, 2, 8, 6]);
returns => 2

https://lodash.com/docs/4.17.15

С помощью 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

В наши дни (в 2022 году) самый эффективный способ получитьmin+maxиз массива - сделать это за одну итерацию, черезreduce.

  • В JavaScript:
      const arr = [3, 0, -2, 5, 9, 4];

const i = arr.reduce((p, c) => {
    p.min = c < p.min ? c : p.min ?? c;
    p.max = c > p.max ? c : p.max ?? c;
    return p;
}, {min: undefined, max: undefined});

console.log(i); //=> { min: -2, max: 9 }

И когда на входе нет данных, он выведет{min: undefined, max: undefined}.

В TypeScript вы просто добавили бы приведение типов, поэтому возвращаемый тип выводится как{min: number, max: number}, а не как{min: any, max: any}:

      const arr = [3, 0, -2, 5, 9, 4];

const i = arr.reduce((p, c) => {
    p.min = c < p.min ? c : p.min ?? c;
    p.max = c > p.max ? c : p.max ?? c;
    return p;
}, {min: undefined as number, max: undefined as number});
//=> {min: number, max: number}

console.log(i); //=> { min: -2, max: 9 }

ОБНОВЛЯТЬ

Следующийkiran goudкомментарий, вот альтернатива, которая использует массивы вместо объектов:

      const i = arr.reduce((p, c) => {
    p[0] = c < p[0] ? c : p[0] ?? c;
    p[1] = c > p[1] ? c : p[1] ?? c;
    return p;
}, [undefined, undefined]);

console.log(i); //=> [-2, 9]

Пытаться

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

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

// TEST - pixel buffer
let arr = Array(200*800*4).fill(0); 
arr.forEach((x,i)=> arr[i]=100-i%101); 

console.log('Max', max(arr));
console.log('Min', min(arr))

Для Math.min/max (+apply) получаем ошибку:

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

// TEST - pixel buffer
let arr = Array(200*800*4).fill(0); 
arr.forEach((x,i)=> arr[i]=100-i%101); 

// Exception: Maximum call stack size exceeded

try {
  let max1= Math.max(...arr);          
} catch(e) { console.error('Math.max :', e.message) }

try {
  let max2= Math.max.apply(null, arr); 
} catch(e) { console.error('Math.max.apply :', e.message) }


// same for min

Если вы используете библиотеку 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 }

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

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

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

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

Если вы используете framework-файл prototype.js, то этот код будет работать нормально:

arr.min();
arr.max();

Документально здесь: Javascript прототип фреймворка для макс.

let arr = [2,5,3,5,6,7,1];

let max = Math.max(...arr); // 7
let min = Math.min(...arr); // 1

Вот простой ванильный подход JS.

function getMinArrayVal(seq){
    var minVal = seq[0];
    for(var i = 0; i<seq.length-1; i++){
        if(minVal < seq[i+1]){
        continue;
        } else {
        minVal = seq[i+1];
        }
    }
    return minVal;
}
minHeight = Math.min.apply({},YourArray);
minKey    = getCertainKey(YourArray,minHeight);
maxHeight = Math.max.apply({},YourArray);
maxKey    = getCertainKey(YourArray,minHeight);
function getCertainKey(array,certainValue){
   for(var key in array){
      if (array[key]==certainValue)
         return key;
   }
} 

Вы можете использовать Array.sort, но вам придется написать простую функцию сортировки чисел, так как по умолчанию используется алфавитный порядок.

Посмотрите на пример 2 здесь.

Тогда вы можете взять arr[0] а также arr[arr.length-1] чтобы получить мин и макс.

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

function minOfArray(arr) {
  var min = Infinity;
  var QUANTUM = 32768;

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

  return min;
}

var min = minOfArray([5, 6, 2, 3, 7]);

Источник: MDN

хорошо, я хотел бы сделать это следующим образом

      const findMaxAndMin = (arr) => {
  if (arr.length <= 0) return -1;
  let min = arr[0];
  let max = arr[0];
  arr.map((n) => {
    n > max ? (max = n) : false;
    n < min ? (min = n) : false;
  });
  return [min, max];
};

Мне нравится подход Линуса Reduce(), особенно для больших массивов. Но если вы знаете, что вам нужны и min, и max, зачем перебирать массив дважды?

Array.prototype.minmax = function () {
  return this.reduce(function (p, v) {
    return [(p[0] < v ? p[0] : v), (p[1] > v ? p[1] : v)];
  }, [this[0], this[0]]);
}

Конечно, если вы предпочитаете итеративный подход, вы можете сделать это тоже:

Array.prototype.minmax = function () {
    var mn = this[0], mx = this[0];
    this.forEach(function (v) {
        if (v < mn) mn = v;
        if (v > mx) mx = v;
    });
    return [mn, mx];
};

Другое решение

         let arr = [1,10,25,15,31,5,7,101];
    let sortedArr = arr.sort((a, b) => a - b)

    let min = sortedArr[0];
    let max = sortedArr[arr.length-1]

    console.log(`min => ${min}. Max => ${max}`)

Чтобы "max" и "min" не были перечислены в цикле "for ... in":

Object.defineProperty(Array.prototype, "max", {
    enumerable: false,
    configurable: false,
    writable: false,    
    value: function() {
        return Math.max.apply(null, this);
    }
});
Object.defineProperty(Array.prototype, "min", {
    enumerable: false,
    configurable: false,
    writable: false,    
    value: function() {
        return Math.min.apply(null, this);
    }
});

Использование:

var x = [10,23,44,21,5];
x.max(); //44
x.min(); //5

Создать простой объект

var myArray = new Array();

myArray = [10,12,14,100];

var getMaxHeight = {
     hight : function( array ){ return Math.max.apply( Math, array );
}

getMaxHeight.hight(myArray);

Чтобы добавить ко многим хорошим ответам здесь, вот версия машинописного текста, которая может обрабатывать списки, где некоторые значенияundefined.

Как это можно использовать:

      const testDates = [
  undefined,
  new Date('July 30, 1986'),
  new Date('July 31, 1986'),
  new Date('August 1, 1986'),
]
const max: Date|undefined = arrayMax(testDates); // Fri Aug 01 1986
const min: Date|undefined = arrayMin(testDates); // Min: Wed Jul 30 1986
const test: Date = arrayMin(testDates); // Static type error
const anotherTest: undefined = arrayMin(testDates); // Static type error

Определения (т.notEmptyопределение взято из этого поста ):

      function arrayMax<T>(values?: (T | null | undefined)[]): T | undefined {
    const nonEmptyValues = filterEmpty(values);
    if (nonEmptyValues.length === 0) {
        return undefined;
    }
    return nonEmptyValues.reduce((a, b) => (a >= b ? a : b), nonEmptyValues[0]);
}

function arrayMin<T>(values?: (T | null | undefined)[]): T | undefined {
    const nonEmptyValues = filterEmpty(values);
    if (nonEmptyValues.length === 0) {
        return undefined;
    }
    return nonEmptyValues.reduce((a, b) => (a <= b ? a : b), nonEmptyValues[0]);
}

function filterEmpty<T>(values?: (T | null | undefined)[] | null): T[] {
    return values?.filter(notEmpty) ?? [];
}

function notEmpty<T>(value: T | null | undefined): value is T {
    if (value === null || value === undefined) return false;
    const testDummy: T = value;
    return true;
}

я не использовалMath.maxкак предложено в документации, потому что таким образом я могу использовать эту функцию с любыми сопоставимыми объектами (если вы знаете, как это ввести, дайте мне знать, чтобы я мог лучше определитьT).

У меня ниже скрипт работает в ndoejs:

 var numbers = [1, 2, 3, 4];
 console.log('Value:: ' + Math.max.apply(null, numbers) ); // 4

Возможно, вы не захотите добавлять методы в прототип Array, которые могут конфликтовать с другими библиотеками.

Я видел множество примеров использования forEach, которые я бы не рекомендовал для больших массивов из-за его низкой производительности по сравнению с циклом for. https://coderwall.com/p/kvzbpa/don-t-use-array-foreach-use-for-instead

Также Math.max(Math, [1,2,3]); Всегда дает мне NaN?

function minArray(a) {
  var min=a[0]; for(var i=0,j=a.length;i<j;i++){min=a[i]<min?a[i]:min;}
  return min;
}

function maxArray(a) {
  var max=a[0]; for(var i=0,j=a.length;i<j;i++){max=a[i]>max?a[i]:max;}
  return max;
}

minArray([1,2,3]); // returns 1

Если у вас есть массив объектов, приведенный ниже пример функции minArray() будет принимать 2 параметра, первый - это массив, а второй - имя ключа для сравнения значения ключа объекта. Функция в этом случае будет возвращать индекс массива, который имеет наименьшее значение ключа.

function minArray(a, key) {
  var min, i, j, index=0;
  if(!key) {
    min=a[0]; 
    for(i=0,j=a.length;i<j;i++){min=a[i]<min?a[i]:min;}
    return min;
  }
  min=a[0][key];
  for(i=0,j=a.length;i<j;i++){
    if(a[i][key]<min) {
      min = a[i][key];
      index = i;
    }
  }
    return index;
}

var a = [{fee: 9}, {fee: 2}, {fee: 5}];

minArray(a, "fee"); // returns 1, as 1 is the proper array index for the 2nd array element.

Если у вас есть сложный объект, вы можете использовать сортировку.... например: если я хочу получить элемент, который содержит значение MAX/MIN ниже objs.

var objs= [
{name:"Apple",value:3},
{name:"Love",value:32},
{name:"Cheese",value:1},
{name:"Pork",value:77},
{name:"Xmas",value:99}        
];

Я сделаю вид:

objs.sort(function(a, b){return a.value-b.value});

Затем:objs[0] это мин, objs[objs.length-1] это Макс.

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

      class SmallestIntegerFinder {
  findSmallestInt(args) {
    return args.reduce((min,item)=>{ return (min<item ? min : item)});
  }
}

class SmallestIntegerFinder {
  findSmallestInt(args) {
    return Math.min(...args)
  }
}

class SmallestIntegerFinder {
  findSmallestInt(args) {
    return Math.min.apply(null, args);
  }
}

class SmallestIntegerFinder {
  findSmallestInt(args) {
    args.sort(function(a, b) {
    return a - b; } )
    return args[0];
  }
}

Вставьте числа, разделенные запятой, и нажмите на событие, которое вы хотите вызвать, т.е. получите максимальное или минимальное число.

        function maximumNumber() {
       
            var numberValue = document.myForm.number.value.split(",");
            var numberArray = [];
    
            for (var i = 0, len = numberValue.length; i < len; i += 1) {
    
                numberArray.push(+numberValue[i]);
    
                var largestNumber = numberArray.reduce(function (x, y) {
                    return (x > y) ? x : y;
                });
            }
    
            document.getElementById("numberOutput").value = largestNumber;
    
        }
    
        function minimumNumber() {
  
            var numberValue = document.myForm.number.value.split(",");
            var numberArray = [];
    
            for (var i = 0, len = numberValue.length; i < len; i += 1) {
    
                numberArray.push(+numberValue[i]);
    
                var smallestNumber = numberArray.reduce(function (x, y) {
                    return (x < y) ? x : y;
                });
            }
    
            document.getElementById("numberOutput").value = smallestNumber;
    
        }
    
    
            function restrictCharacters(evt) {
    
                evt = (evt) ? evt : window.event;
                var charCode = (evt.which) ? evt.which : evt.keyCode;
                if (((charCode >= '48') && (charCode <= '57')) || (charCode == '44')) {
                    return true;
                }
                else {
                    return false;
                }
            }
    
    <div>    
            <form name="myForm">
            <table>
            <tr>
                <td>Insert Number</td>
               
                <td><input type="text" name="number" id="number" onkeypress="return restrictCharacters(event);" /></td>
                
                <td><input type="button" value="Maximum" onclick="maximumNumber();" /></td>
                
                <td><input type="button" value="Minimum" onclick="minimumNumber();"/></td>
                
                <td><input type="text" id="numberOutput" name="numberOutput" /></td>
    
            </tr>
            </table>
            </form>
        </div>

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

Линейный, почти чисто функциональный подход

var min=[0, 29, 25].map((function(max) {max=-Infinity; return function(e) {return max=Math.max(max, e);}})())[0]

Больше примеров:

Нахождение минимального значения

function getMin(arr) {
    return (ar || [0, 29, 25]).
        map((function(max) {max=-Infinity; return function(e) {return max=Math.max(max, e);}})())[0];
}

или используя Array.map метод с переменным замыканием

function getMin(arrObjs) {
    return (arrObjs || [{val: 0}, {val: 29}, {val: 25}]).
        map((function(max) {max=-Infinity; return function(e) {return max=(max.val>e.val?max:e);}})())[0];
}

Определение максимального значения

function getMax(arr) {
    return (ar || [0, 29, 25]).
        map((function(v) {v=Infinity; return function(e) {return v=Math.min(v, e);}})())[0];
}

для массива объектов

function getMax(arrObjs) {
    return (arrObjs || [{val: 0}, {val: 29}, {val: 25}]).
        map((function(v) {v=-Infinity; return function(e) {return v=(v.val<e.val?v:e);}})())[0];
}

Если вам нужна производительность, то это лучший способ для небольших массивов:

var min = 99999;
var max = 0;
for(var i = 0; i < v.length; i++)
{
    if(v[i] < min)
    {
        min = v[i];
    }
    if(v[i] >= max)
    {
        max = v[i];
    }
}

Рекурсивное решение проблемы

const findMinMax = (arr, max, min, i) => arr.length === i ? {
    min,
    max
  } :
  findMinMax(
    arr,
    arr[i] > max ? arr[i] : max,
    arr[i] < min ? arr[i] : min,
    ++i)

const arr = [5, 34, 2, 1, 6, 7, 9, 3];
const max = findMinMax(arr, arr[0], arr[1], 0)
console.log(max);

Вот еще один пример. Рассчитайте значение Max/Min из массива с помощью lodash.

let array = [100, 0, 50];
var func = _.over(Math.max, Math.min);
var [max, min] = func(...array);
// => [100, 0]
console.log(max);
console.log(min);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.js"></script>

Другие вопросы по тегам