Reputation: 12013
How can I easily obtain the min or max element of a JavaScript array?
Example pseudocode:
let array = [100, 0, 50]
array.min() //=> 0
array.max() //=> 100
Upvotes: 1197
Views: 1680834
Reputation: 20912
Using them with an array containing a large number of items (more than ~10⁷ items, depending on the user's browser) most likely will crash and give the following error message:
const arr = Array.from(Array(1000000).keys());
Math.min(arr);
Math.max(arr);
Uncaught RangeError: Maximum call stack size exceeded
Some browsers might return a NaN
value instead. It might be a better way to handle errors, but it doesn't solve the problem just yet.
Instead, for very large numbers, consider using something like this:
function maxValue(arr) {
return arr.reduce((max, val) => max > val ? max : val)
}
const arr = Array.from(Array(1000000).keys());
console.log(maxValue(arr)); // 999999
Better run-time:
function maxValue(arr) {
let max = arr[0];
for (let val of arr) {
if (val > max) {
max = val;
}
}
return max;
}
const arr = Array.from(Array(1000000).keys());
console.log(maxValue(arr)); // 999999
Get both Min and 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] });
}
const arr = Array.from(Array(1000000).keys());
console.log(getMinMax(arr)); // {"min":0,"max":999999}
Better run-time*:
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 };
}
const arr = Array.from(Array(1000000).keys());
console.log(getMinMax(arr)); // {"min":0,"max":999999}
* Tested with 1,000,000 items:
Just for reference, the 1st function run-time (on my machine) was 15.84ms vs. 2nd function with only 4.32ms.
Upvotes: 66
Reputation: 9253
There are several approaches you can use:
Math.min()
and 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
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];
}
}
Upvotes: 6
Reputation: 25940
In this day and age (in 2022), the most efficient way to get min
+ max
from an array is to do it in a single iteration, via reduce
.
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 }
And when the input has no data, it will output {min: undefined, max: undefined}
.
In TypeScript, you would just add type casting, so the return type is inferred as {min: number | undefined, max: number | undefined}
, and not as {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, max: undefined} as { min: number | undefined, max: number | undefined });
console.log(i); //=> { min: -2, max: 9 }
UPDATE
Following kiran goud
comment, here's an alternative that uses arrays instead of objects:
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]
Upvotes: 5
Reputation: 10962
To add to the many good answers here, here is a typescript version that can handle lists where some values are undefined
.
How it can be used:
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
The definitions (the notEmpty
definition is from this post):
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;
}
I didn't use the Math.max
function as suggested in the documentation because this way I can use this function with any comparable objects (if you know how to type this let me know so I can better define T
).
Upvotes: 1
Reputation: 1287
For learning purpose, you can do it by using variables and for loop without using built-in functions.
// Input sample data to the function
var arr = [-1, 0, 3, 100, 99, 2, 99];
// Just to show the result
console.log(findMinMax(arr));
function findMinMax(arr) {
let arraySize = arr.length;
if (arraySize > 0) {
var MaxNumber = MinNumber = arr[0];
for (var i = 0; i <= arraySize; i++) {
if (arr[i] > MaxNumber) {
MaxNumber = arr[i];
}else if(arr[i] < MinNumber) {
MinNumber = arr[i];
}
}
var minMax = [MinNumber,MaxNumber];
return minMax;
} else {
return 0;
}
}
Upvotes: 0
Reputation: 24105
How about augmenting the built-in Array object to use Math.max
/Math.min
instead:
Array.prototype.max = function() {
return Math.max.apply(null, this);
};
Array.prototype.min = function() {
return Math.min.apply(null, this);
};
let p = [35,2,65,7,8,9,12,121,33,99];
console.log(`Max value is: ${p.max()}` +
`\nMin value is: ${p.min()}`);
Here is a JSFiddle.
Augmenting the built-ins can cause collisions with other libraries (some see), so you may be more comfortable with just apply
'ing Math.xxx()
to your array directly:
var min = Math.min.apply(null, arr),
max = Math.max.apply(null, arr);
Alternately, assuming your browser supports ECMAScript 6, you can use spread syntax which functions similarly to the apply
method:
var min = Math.min( ...arr ),
max = Math.max( ...arr );
Upvotes: 1105
Reputation: 31
Alternative Solns
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];
}
}
Upvotes: 0
Reputation: 24301
For big arrays (~10⁷ elements), Math.min
and Math.max
both produces the following error in Node.js.
RangeError: Maximum call stack size exceeded
A more robust solution is to not add every element to the call stack, but to instead pass an array:
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 );
});
}
If you are concerned about speed, the following code is ~3 times faster then Math.max.apply
is on my computer. See https://jsben.ch/JPOyL.
function arrayMin(arr) {
var len = arr.length, min = Infinity;
while (len--) {
if (arr[len] < min) {
min = arr[len];
}
}
return min;
};
function arrayMax(arr) {
var len = arr.length, max = -Infinity;
while (len--) {
if (arr[len] > max) {
max = arr[len];
}
}
return max;
};
If your arrays contains strings instead of numbers, you also need to coerce them into numbers. The below code does that, but it slows the code down ~10 times on my machine. See https://jsben.ch/uPipD.
function arrayMin(arr) {
var len = arr.length, min = Infinity;
while (len--) {
if (Number(arr[len]) < min) {
min = Number(arr[len]);
}
}
return min;
};
function arrayMax(arr) {
var len = arr.length, max = -Infinity;
while (len--) {
if (Number(arr[len]) > max) {
max = Number(arr[len]);
}
}
return max;
};
Upvotes: 299
Reputation: 1095
Another solution
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}`)
Upvotes: 1
Reputation: 93541
Using spread operator (ES6)
Math.max(...array) // The same with "min" => Math.min(...array)
const array = [10, 2, 33, 4, 5];
console.log(
Math.max(...array)
)
Upvotes: 366
Reputation: 426
well I would like to do this in the below way
const findMaxAndMin = (arr) => {
if (arr.length <= 0) return -1;
let min = arr[0];
let max = arr[0];
arr.forEach((n) => {
n > max ? (max = n) : false;
n < min ? (min = n) : false;
});
return [min, max];
};
Upvotes: 1
Reputation: 8586
Aside using the math function max and min, another function to use is the built in function of sort(): here we go
const nums = [12, 67, 58, 30].sort((x, y) =>
x - y)
let min_val = nums[0]
let max_val = nums[nums.length -1]
Upvotes: 10
Reputation: 5272
let arr=[20,8,29,76,7,21,9]
Math.max.apply( Math, arr ); // 76
Upvotes: 9
Reputation: 1363
let array = [267, 306, 108] let longest = Math.max(...array);
Upvotes: 12
Reputation: 89507
For a concise, modern solution, one can perform a reduce
operation over the array, keeping track of the current minimum and maximum values, so the array is only iterated over once (which is optimal). Destructuring assignment is used here for succinctness.
let array = [100, 0, 50];
let [min, max] = array.reduce(([prevMin,prevMax], curr)=>
[Math.min(prevMin, curr), Math.max(prevMax, curr)], [Infinity, -Infinity]);
console.log("Min:", min);
console.log("Max:", max);
To only find either the minimum or maximum, we can use perform a reduce operation in much the same way, but we only need to keep track of the previous optimal value. This method is better than using apply
as it will not cause errors when the array is too large for the stack.
const arr = [-1, 9, 3, -6, 35];
//Only find minimum
const min = arr.reduce((a,b)=>Math.min(a,b), Infinity);
console.log("Min:", min);//-6
//Only find maximum
const max = arr.reduce((a,b)=>Math.max(a,b), -Infinity);
console.log("Max:", max);//35
Upvotes: 19
Reputation: 60093
For an array containing objects instead of numbers:
arr = [
{ name: 'a', value: 5 },
{ name: 'b', value: 3 },
{ name: 'c', value: 4 }
]
You can use reduce
to get the element with the smallest value (min)
arr.reduce((a, b) => a.value < b.value ? a : b)
// { name: 'b', value: 3 }
or the largest value (max)
arr.reduce((a, b) => a.value > b.value ? a : b)
// { name: 'a', value: 5 }
Upvotes: 10
Reputation: 771
array.sort((a, b) => b - a)[0];
Gives you the maximum value in an array of numbers.
array.sort((a, b) => a - b)[0];
Gives you the minimum value in an array of numbers.
let array = [0,20,45,85,41,5,7,85,90,111];
let maximum = array.sort((a, b) => b - a)[0];
let minimum = array.sort((a, b) => a - b)[0];
console.log(minimum, maximum)
Upvotes: 10
Reputation: 2370
Two ways are shorter and easy:
let arr = [2, 6, 1, 0]
Way 1:
let max = Math.max.apply(null, arr)
Way 2:
let max = arr.reduce(function(a, b) {
return Math.max(a, b);
});
Upvotes: 45
Reputation: 1096
You can use lodash's methods
_.max([4, 2, 8, 6]);
returns => 8
https://lodash.com/docs/4.17.15#max
_.min([4, 2, 8, 6]);
returns => 2
https://lodash.com/docs/4.17.15#min
Upvotes: 5
Reputation: 4250
A simple solution to find the minimum value over an Array
of elements is to use the Array
prototype function reduce
:
A = [4,3,-9,-2,2,1];
A.reduce((min, val) => val < min ? val : min, A[0]); // returns -9
or using JavaScript's built-in Math.Min() function (thanks @Tenflex):
A.reduce((min,val) => Math.min(min,val), A[0]);
This sets min
to A[0]
, and then checks for A[1]...A[n]
whether it is strictly less than the current min
. If A[i] < min
then min
is updated to A[i]
. When all array elements has been processed, min
is returned as the result.
EDIT: Include position of minimum value:
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 }
Upvotes: 22
Reputation: 13723
A recursive solution to the problem
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);
Upvotes: 0
Reputation: 303
Here's a plain vanilla JS approach.
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;
}
Upvotes: 2
Reputation: 92727
Try
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))
For Math.min/max (+apply) we get error:
Maximum call stack size exceeded (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
Upvotes: 4
Reputation: 31182
// 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];
}
}
The official MDN docs on Math.max()
already covers this issue:
The following function uses Function.prototype.apply() to find the maximum element in a numeric array.
getMaxOfArray([1, 2, 3])
is equivalent toMath.max(1, 2, 3)
, but you can usegetMaxOfArray()
on programmatically constructed arrays of any size.function getMaxOfArray(numArray) { return Math.max.apply(null, numArray); }
Or with the new spread operator, getting the maximum of an array becomes a lot easier.
var arr = [1, 2, 3]; var max = Math.max(...arr);
According to MDN the apply
and spread solutions had a limitation of 65536 that came from the limit of the maximum number of arguments:
But beware: in using apply this way, you run the risk of exceeding the JavaScript engine's argument length limit. The consequences of applying a function with too many arguments (think more than tens of thousands of arguments) vary across engines (JavaScriptCore has hard-coded argument limit of 65536), because the limit (indeed even the nature of any excessively-large-stack behavior) is unspecified. Some engines will throw an exception. More perniciously, others will arbitrarily limit the number of arguments actually passed to the applied function. To illustrate this latter case: if such an engine had a limit of four arguments (actual limits are of course significantly higher), it would be as if the arguments 5, 6, 2, 3 had been passed to apply in the examples above, rather than the full array.
They even provide a hybrid solution which doesn't really have good performance compared to other solutions. See performance test below for more.
In 2019 the actual limit is the maximum size of the call stack. For modern Chromium based desktop browsers this means that when it comes to finding min/max with apply
or spread, practically the maximum size for numbers only arrays is ~120000. Above this, there will be a stack overflow and the following error will be thrown:
RangeError: Maximum call stack size exceeded
With the script below (based on this blog post), by catching that error you can calculate the limit for your specific environment.
Warning! Running this script takes time and depending on the performance of your system it might slow or crash your browser/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;
}
}
Based on the test in EscapeNetscape's comment I created some benchmarks that tests 5 different methods on a random number only array with 100000 items.
In 2019, the results show that the standard loop (which BTW doesn't have the size limitation) is the fastest everywhere. apply
and spread comes closely after it, then much later MDN's hybrid solution then reduce
as the slowest.
Almost all tests gave the same results, except for one where spread somewhy ended up being the slowest.
If you step up your array to have 1 million items, things start to break and you are left with the standard loop as a fast solution and reduce
as a slower.
var testArrayLength = 100000
var testArray = Array.from({length: testArrayLength}, () => Math.floor(Math.random() * 2000000));
// ES6 spread
Math.min(...testArray);
Math.max(...testArray);
// reduce
testArray.reduce(function(a, b) {
return Math.max(a, b);
});
testArray.reduce(function(a, b) {
return Math.min(a, b);
});
// apply
Math.min.apply(Math, testArray);
Math.max.apply(Math, testArray);
// standard loop
let max = testArray[0];
for (let i = 1; i < testArrayLength; ++i) {
if (testArray[i] > max) {
max = testArray[i];
}
}
let min = testArray[0];
for (let i = 1; i < testArrayLength; ++i) {
if (testArray[i] < min) {
min = testArray[i];
}
}
// MDN hibrid soltuion
// Source: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/apply#Using_apply_and_built-in_functions
function minOfArray(arr) {
var min = Infinity;
var QUANTUM = 32768;
for (var i = 0, len = arr.length; i < len; i += QUANTUM) {
var submin = Math.min.apply(null, arr.slice(i, Math.min(i + QUANTUM, len)));
min = Math.min(submin, min);
}
return min;
}
minOfArray(testArray);
function maxOfArray(arr) {
var max = -Infinity;
var QUANTUM = 32768;
for (var i = 0, len = arr.length; i < len; i += QUANTUM) {
var submax = Math.max.apply(null, arr.slice(i, Math.max(i + QUANTUM, len)));
max = Math.max(submax, max);
}
return max;
}
maxOfArray(testArray);
Upvotes: 187
Reputation: 3383
let arr = [2,5,3,5,6,7,1];
let max = Math.max(...arr); // 7
let min = Math.min(...arr); // 1
Upvotes: 3
Reputation: 17498
Here is one more example. Calculate the Max/Min value from an array with 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>
Upvotes: -1
Reputation: 150
Insert the numbers seperated by a comma and click on the event you want to call ie Get the Max or min number.
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>
Upvotes: 0
Reputation: 497
The following code works for me :
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); });
Upvotes: 9
Reputation: 7186
If you're paranoid like me about using Math.max.apply
(which could cause errors when given large arrays according to MDN), try this:
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);
});
}
Or, in 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));
}
The anonymous functions are unfortunately necessary (instead of using Math.max.bind(Math)
because reduce
doesn't just pass a
and b
to its function, but also i
and a reference to the array itself, so we have to ensure we don't try to call max
on those as well.
Upvotes: 74