How can I easily obtain the min or max element of a JavaScript Array?
Example Psuedocode:
let array = [100, 0, 50]
array.min() //=> 0
array.max()
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.
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); });
Iterate through, keeping track as you go.
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 );
This will leave min/max null if there are no elements in the array. Will set min and max in one pass if the array has any elements.
You could also extend Array with a range
method using the above to allow reuse and improve on readability. See a working fiddle at 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 }
};
Used as
var arr = [3, 9, 22, -7, 44, 18, 7, 9, 15];
var range = arr.range();
console.log(range.min);
console.log(range.max);
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);
});
If you use the library sugar.js, you can write arr.min() and arr.max() as you suggest. You can also get min and max values from non-numeric arrays.
min( map , all = false ) Returns the element in the array with the lowest value. map may be a function mapping the value to be checked or a string acting as a shortcut. If all is true, will return all min values in an array.
max( map , all = false ) Returns the element in the array with the greatest value. map may be a function mapping the value to be checked or a string acting as a shortcut. If all is true, will return all max values in an array.
Examples:
[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"]
Libraries like Lo-Dash and underscore.js also provide similar powerful min and max functions:
Example from 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 }
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 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;
};
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 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;
};