如何轻松获取 JavaScript 数组的最小或最大元素?
示例伪代码:
let array = [100, 0, 50]
array.min() //=> 0
array.max() //=> 100
如何轻松获取 JavaScript 数组的最小或最大元素?
示例伪代码:
let array = [100, 0, 50]
array.min() //=> 0
array.max() //=> 100
如何增加内置 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 );
var max_of_array = Math.max.apply(Math, array);
有关完整讨论,请参阅:http : //aaroncrane.co.uk/2008/11/javascript_max_api/
对于大阵列(〜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;
};
// 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()
已经涵盖了这个问题:
以下函数使用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的限制:
但请注意:以这种方式使用 apply 时,您可能会面临超出 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
是最慢的。
几乎所有的测试都给出了相同的结果,除了一个最终传播速度最慢的测试。
如果您将数组增加到 100 万个项目,事情就会开始破裂,您将使用标准循环作为快速解决方案和reduce
较慢的解决方案。