如何轻松获得JavaScript数组的min或max元素?
伪代码示例:
let array = [100, 0, 50]
array.min() //=> 0
array.max() //=> 100
#1楼
另一种方法是:
var arrayMax = Function.prototype.apply.bind(Math.max, null);
用法:
var max = arrayMax([2, 5, 1]);
#2楼
对于大数组(〜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 );
});
}
如果您担心速度,那么下面的代码Math.max.apply
快3倍。 参见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;
};
#3楼
这可能适合您的目的。
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;
}
#4楼
如何扩充内置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 );
#5楼
反复进行,随时随地进行跟踪。
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。 如果数组中有任何元素,将一遍设置最小值和最大值。
您还可以使用上述方法使用range
方法扩展Array,以允许重用并提高可读性。 请参阅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);
#6楼
如果您正在使用原型,ChaosPandion的解决方案就可以使用。 如果没有,请考虑以下问题:
Array.max = function( array ){
return Math.max.apply( Math, array );
};
Array.min = function( array ){
return Math.min.apply( Math, array );
};
如果数组值不是整数,则上面的代码将返回NaN,因此您应该构建一些功能来避免这种情况。 否则,它将起作用。
#7楼
您可以通过扩展Array类型来做到这一点:
Array.max = function( array ){
return Math.max.apply( Math, array );
};
Array.min = function( array ){
return Math.min.apply( Math, array );
};
从这里提振(约翰·雷西格)
#8楼
其他人已经给出了一些增加Array.prototype
解决方案。 我在此答案中想要澄清的是应该是Math.min.apply( Math, array )
还是Math.min.apply( null, array )
。 那么应该使用什么上下文, Math
或null
?
当将null
用作要apply
的上下文时,该上下文将默认为全局对象(对于浏览器为window
对象)。 将Math
对象作为上下文传递是正确的解决方案,但也不会伤害传递null
。 这是装饰Math.max
函数时null
可能引起麻烦的示例:
// 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
。 如果我们将Math
替换为null
,那么事情将会按预期进行,并且字符串“ foo”将被打印到屏幕上(我使用Mozilla Rhino对此进行了测试)。
您几乎可以假设没有人装饰过Math.max
因此,传递null
将毫无问题。
#9楼
我很惊讶没有人提到减少功能。
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]
#10楼
这是一种从对象数组中获取最大值的方法。 创建一个副本(带有切片),然后按降序对副本进行排序并获取第一项。
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;
#11楼
我遇到了同样的问题,我需要获取数组的最小值和最大值,令我惊讶的是,没有用于数组的内置函数。 看了很多书后,我决定自己测试“前三名”解决方案:
- 离散解决方案:一个FOR循环,根据当前的最大值和/或最小值检查数组的每个元素;
- APPLY解决方案:使用apply(null,array)将数组发送到Math.max和/或Math.min内部函数;
- 减少解决方案:使用reduce(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个随机整数,在具有Windows Vista的intel Pentium 4 2.99GHz台式机上的Mozilla Firefox 28.0上,每个函数执行了10,000次。 时间以秒为单位,由performance.now()函数检索。 结果是这些,带有3个小数位数和标准偏差:
- 离散解:平均值= 0.161s,sd = 0.078
- 应用解决方案:平均值= 3.571s,标准差= 0.487
- 减少求解:均值= 0.350s,标准差= 0.044
REDUCE解决方案比离散解决方案慢了117%。 APPLY解决方案比离散解决方案更糟,慢了2,118%。 此外,正如Peter所言,它不适用于大型数组(大约超过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,标准偏差= 0.094
因此,它比简单的离散解决方案要慢35%,但是它一次可以检索最大值和最小值(任何其他解决方案至少要检索两倍)。 一旦OP需要两个值,离散解决方案将是最佳选择(即使是两个独立的函数,一个用于计算最大值,另一个用于计算最小值,它们也会胜过第二个最佳方案REDUCE解决方案)。
#12楼
如果使用库sugar.js ,则可以按照您的建议编写arr.min()和arr.max() 。 您还可以从非数值数组中获取最小值和最大值。
min(map,all = false)返回数组中具有最低值的元素。 map可以是映射要检查的值的函数,也可以是用作快捷方式的字符串。 如果all为true,则将返回数组中的所有min值。
max(map,all = false)返回数组中具有最大值的元素。 map可以是映射要检查的值的函数,也可以是用作快捷方式的字符串。 如果all为true,则将返回数组中的所有最大值。
例子:
[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 }
#13楼
您可以在项目中的任何地方使用以下功能:
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
#14楼
简单的东西,真的。
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());
#15楼
.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']
#16楼
tl; dr
// 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解决方案
Math.max()
上的官方MDN文档已经涵盖了此问题:
以下函数使用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注释中的测试,我创建了一些基准测试,该基准对具有100000个项目的仅随机数数组测试5种不同的方法。
在2019年,结果显示标准循环 (BTW没有大小限制)是最快的。 apply
和传播紧随其后,然后很晚MDN的混合解决方案以最慢的速度reduce
。
几乎所有测试都给出了相同的结果,唯一不同的是,由于某种原因传播速度最慢。
如果您增加阵列以拥有一百万个项目,那么事情就会开始崩溃,您将只能使用标准循环作为快速解决方案,而reduce
速度则要慢一些。
JSPerf基准
JSBen基准
JSBench.me基准
基准源代码
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);
#17楼
如果您像我一样对使用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
传递给函数,而且还传递a
i
和对数组本身的引用,因此我们必须确保不这样做也不要尝试对这些调用max
。
#18楼
使用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
#19楼
使用传播算子(ES6)
Math.max(...array); // the same with "min" => Math.min(...array);
const array = [10, 2, 33, 4, 5]; console.log( Math.max(...array) )
#20楼
我以为我会分享我简单易懂的解决方案。
对于分钟:
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);
#21楼
https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/Math/max
function getMaxOfArray(numArray) { return Math.max.apply(null, numArray); } var arr = [100, 0, 50]; console.log(getMaxOfArray(arr))
这对我有用。
#22楼
以下代码对我有用:
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); });
#23楼
在元素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
作为结果。
#24楼
两种方法更短,更容易:
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);
});
#25楼
最小数学和最大数学
Math.min
和Math.max
都是递归操作,它们很可能会占用较大的数组(大于约10个项目)。
相反,您可以使用旧的javascript循环,如下所示:
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.84ms,而第二个函数运行时仅为4.32ms。
#26楼
let arr = [2,5,3,5,6,7,1];
let max = Math.max(...arr); // 7
let min = Math.min(...arr); // 1
#27楼
尝试
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(+应用),我们得到错误:
超过最大通话堆栈大小(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
#28楼
var max_of_array = Math.max.apply(Math, array);
有关完整的讨论,请参见: http : //aaroncrane.co.uk/2008/11/javascript_max_api/
#29楼
对于大数组(〜10个元素), Math.min
和Math.max
在node.js中产生RangeError(超出最大调用堆栈大小)。
对于大型阵列,一种快速而肮脏的解决方案是:
Array.prototype.min = function() {
var r = this[0];
this.forEach(function(v,i,a){if (v<r) r=v;});
return r;
};
#30楼
如果您使用的是prototype.js框架,则此代码可以正常运行:
arr.min();
arr.max();
此处记录: max的Javascript原型框架