在JavaScript中查找数组的最小/最大元素

在JavaScript中查找数组的最小/最大元素,javascript,Javascript,如何轻松获取JavaScript数组的min或max元素 伪代码示例: let array = [100, 0, 50] array.min() //=> 0 array.max() //=> 100 这可能适合你的目的 Array.prototype.min = function(comparer) { if (this.length === 0) return null; if (this.length === 1) return this[0];

如何轻松获取JavaScript数组的min或max元素

伪代码示例:

let array = [100, 0, 50]

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

这可能适合你的目的

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;
}

如何扩展内置数组对象以使用/替代:

这是一本书

扩充内置函数可能会导致与某些库发生冲突,因此您可能更愿意直接将Math.xxx应用于阵列:

var min = Math.min.apply(null, arr),
    max = Math.max.apply(null, arr);
或者,假设您的浏览器支持ECMAScript 6,则可以使用与apply方法类似的函数:


反复浏览,边走边跟踪

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 );
用作

var arr = [3, 9, 22, -7, 44, 18, 7, 9, 15];

var range = arr.range();

console.log(range.min);
console.log(range.max);

如果您使用的是Prototype,则Chaosption的解决方案有效。如果不是,考虑一下:

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

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

如果数组值不是整数,则上述函数将返回NaN,因此您应该构建一些功能来避免这种情况。否则这将起作用。

您可以通过扩展数组类型来实现:

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

在John Resig的推动下,其他人已经给出了一些解决方案,在这些解决方案中,他们增强了Array.prototype。在这个答案中,我只想澄清它应该是Math.min.apply Math,array还是Math.min.apply null,array。那么应该使用什么上下文,Math还是null

当传递null作为要应用的上下文时,上下文将默认为全局对象,在浏览器中为窗口对象。将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进行计算,window.foo未定义。如果我们用Math替换null,事情将按预期进行,字符串foo将被打印到我使用它测试的屏幕上

您几乎可以假设没有人修饰Math.max,因此,传递null将毫无问题地工作

var max_of_array = Math.max.apply(Math, array);
有关详细讨论,请参阅:

对于大型阵列~10⁷ 元素、Math.min和Math.max会导致RangeError超过node.js中的最大调用堆栈大小

对于大型阵列,快速脏的解决方案是:

Array.prototype.min = function() {
    var r = this[0];
    this.forEach(function(v,i,a){if (v<r) r=v;});
    return r;
};
还有一种方法:

var arrayMax = Function.prototype.apply.bind(Math.max, null);
用法:

var max = arrayMax([2, 5, 1]);

对于大型阵列~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 );
  });
}
如果数组包含字符串而不是数字,则还需要将其强制为数字。下面的代码可以做到这一点,但在我的机器上,它会将代码速度降低约10倍。看


我很惊讶没有人提到reduce函数

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]

下面是一种从对象数组中获取最大值的方法。使用slice创建一个副本,然后按降序对副本排序并获取第一项

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; 

我也有同样的问题,我需要获得数组的最小值和最大值,令我惊讶的是,数组没有内置函数。在阅读了很多之后,我决定亲自测试前3个解决方案:

离散解决方案:一个FOR循环,用于根据当前最大值和/或最小值检查阵列的每个元素; 应用解决方案:使用applynull、array将数组发送到Math.max和/或Math.min内部函数; REDUCE解决方案:使用reducefunction对数组的每个元素递归检查。 测试代码如下:

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中填充了100000个随机整数,每个函数在装有Windows Vista的英特尔奔腾4 2.99GHz桌面上的Mozilla Firefox 28.0上执行10000次。时间以秒为单位,由performance.now函数检索。结果如下,有3个小数位数和标准偏差:

离散解:平均值=0.161s,标准差=0.078 应用溶液:平均值=3.571s,标准差=0.487 还原溶液:平均值=0.350s,标准偏差=0.044 还原溶液比离散溶液慢117%。应用解决方案更差,比离散解决方案慢2118%。此外,正如Peter所观察到的,它不适用于超过1000000个元素的大型阵列

另外,为了完成测试,我测试了这个扩展的离散代码:

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解决方案。

您可以在项目中的任何位置使用以下函数:

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
简单的东西,真的

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());
.apply通常用于使用参数值列表调用变量函数时,例如

Math.max(...[10, 20], 50); // 50
Math.max(...[-10, -20], 50); // 50
该函数返回零个或多个数字中的最大值

Math.max(10, 20); // 20
Math.max(-10, -20); // -10
Math.max(-10, 20); // 20
马克斯 方法不允许传入数组。如果您有一个需要获取最大值的值列表,通常可以使用调用此函数,例如

但是,从ECMAScript 6开始,您可以使用:

spread运算符允许在函数调用需要多个参数或数组文字需要多个元素的地方展开表达式

使用spread运算符,可以将上述内容改写为:

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等组合

tl;博士 //对于常规阵列: var max=数学最大值…数组编号; //对于包含数万项的阵列: 设max=testArray[0]; 对于let i=1;i<测试长度++我{ 如果testArray[i]>max{ max=testArray[i]; } } MDN解决方案 本报告已经涵盖了这一问题:

以下函数用于查找数值数组中的最大元素。getMaxOfArray[1,2,3]相当于Math.max1,2,3,但您可以在以编程方式构造的任意大小的数组上使用getMaxOfArray

function getMaxOfArray(numArray) {
    return Math.max.apply(null, numArray);
}
function getMaxOfArray(numArray) {
  return Math.max.apply(null, numArray);
}
或者,使用新的,获得最大的数组变得容易得多

var arr = [1, 2, 3];
var max = Math.max(...arr);
var arr = [1, 2, 3];
var max = Math.max(...arr); // 3
var min = Math.min(...arr); // 1
数组的最大大小 apply和spread解决方案的最大参数数限制为65536个:

但要注意:以这种方式使用apply,可能会超出JavaScript引擎的参数长度限制。应用参数过多的函数的后果是,不同引擎中的参数差异超过了上万个JavaScriptCore的硬编码参数限制为65536,因为该限制甚至连任何超大堆栈行为的性质都未指定。某些引擎将抛出异常。更有害的是,其他人会任意限制实际传递给应用函数的参数数量。为了说明后一种情况:如果这样一个引擎有四个参数的限制,那么实际限制当然要高得多,这就好像参数5、6、2、3已经传递到上面的示例中,而不是整个数组中

它们甚至提供了一种混合解决方案,与其他解决方案相比,它的性能并不好。有关更多信息,请参阅下面的性能测试

2019年,实际限制是调用堆栈的最大大小。对于基于Chromium的现代桌面浏览器来说,这意味着在使用apply或spread查找min/max时,仅数字数组的最大大小实际上是~120000。在此之上,将出现堆栈溢出,并将抛出以下错误:

RangeError:超出了最大调用堆栈大小

使用以下基于的脚本,通过捕获该错误,您可以计算特定环境的限制

警告!运行此脚本需要时间,根据系统的性能,它可能会减慢浏览器/系统的速度或使其崩溃

设testArray=Array.from{length:10000},=>Math.floorMath.random*2000000; 对于i=10000;i<1000000++我{ testArray.pushMath.floorMath.random*2000000; 试一试{ Math.max.applynull,testArray; }抓住e{ console.logi; 打破 }
} 如果您像我一样对使用Math.max.apply心存疑虑,在给定大数组时可能会导致错误,请尝试以下方法:

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.bindMath,因为reduce不只是将a和b传递给它的函数,还传递i和对数组本身的引用,所以我们必须确保我们也不会尝试在这些函数上调用max。

使用Math.max或Math.min

以下函数使用function.prototype.apply查找数值数组中的最大元素。getMaxOfArray[1,2,3]相当于Math.max1,2,3,但您可以在以编程方式构造的任意大小的数组上使用getMaxOfArray

function getMaxOfArray(numArray) {
    return Math.max.apply(null, numArray);
}
function getMaxOfArray(numArray) {
  return Math.max.apply(null, numArray);
}
或者使用新的spread操作符,获得阵列的最大值变得容易得多

var arr = [1, 2, 3];
var max = Math.max(...arr);
var arr = [1, 2, 3];
var max = Math.max(...arr); // 3
var min = Math.min(...arr); // 1

使用扩展运算符ES6

Math.max(...array);  // the same with "min" => Math.min(...array);
常量数组=[10,2,33,4,5]; console.log 数学,最大…数组
我想我会分享我简单易懂的解决方案

对于min:

var-arr=[3,4,12,1,0,5]; var min=arr[0]; 对于var k=1;kconsole.loggetMaxOfArrayarr下面的代码对我很有用:

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

查找元素数组的最小值的一个简单解决方案是使用数组原型函数reduce:

这将min设置为[0],然后检查[1]…A[n]是否严格小于当前min。如果[i] 编辑:包括最小值的位置:

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 }

有两种方法既短又简单:

let arr = [2, 6, 1, 0]
方式1:

方式2:

替代方法 Math.min和Math.max是从项目集合中获取最小和最大项目的好方法,但是,重要的是要注意它可能附带的一些空洞。 将它们与包含大量超过10个项目的数组一起使用⁷ 项目,取决于用户的浏览器,最有可能崩溃并给出以下错误消息:

const arr = Array.from(Array(1000000).keys());
Math.min(arr);
Math.max(arr);
未捕获范围错误:超过最大调用堆栈大小

更新 最新的浏览器可能会返回NaN。这可能是处理错误的更好方法,但是它还不能解决问题

相反,考虑使用类似的东西:

function maxValue(arr) {
  return arr.reduce((max, val) => max > val ? max : val)
}
或者使用更好的运行时:

function maxValue(arr) {
  let max = arr[0];

  for (let val of arr) {
    if (val > max) {
      max = val;
    }
  }
  return 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] });
}
或者使用更好的运行时*:

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 };
}
*使用1000000个项目进行测试:
仅供参考,我的机器上第一个函数的运行时间是15.84ms,而第二个函数的运行时间只有4.32ms。

除了使用数学函数max和min外,另一个要使用的函数是内置的sort函数:我们开始吧

const nums = [12, 67, 58, 30].sort((x, y) => 
x -  y)
let min_val = nums[0]
let max_val = nums[nums.length -1]
提供数字数组中的最大值

array.sort((a, b) => a - b)[0];
提供数字数组中的最小值

array.sort((a, b) => a - b)[0];
设数组=[0,20,45,85,41,5,7,85,90111]; 设max=array.sorta,b=>b-a[0]; 设minimum=array.sorta,b=>a-b[0];
console.logminimum,maximum对于简洁、现代的解决方案,可以在数组上执行操作,跟踪当前的最小值和最大值,因此数组只迭代一次,这是最佳的。这里使用的是简洁

让数组=[100,0,50]; 让[min,max]=数组。减少[prevMin,prevMax],curr=> [Math.minprevMin,curr,Math.maxprevMax,curr],[Infinity,-Infinity]; 控制台。logMin:,min;
控制台。logMax:,max 让数组=[267306108]
设longest=Math.max…数组

jeerose,你为什么有数学,当Roatin Marth只有空值时,这是一个数值,这是?@HankH:在我自己的答案的评论中看到我对你评论的回应。我不明白你说的Chaospanion的解决方案在你使用原型的情况下起作用是什么意思。除了使用数学对象作为上下文之外,您的解决方案有什么不同?对不起,我的意思是,如果您扩展原型,您的解决方案将起作用。抱歉。那么jeerose和Chaospanion哪一个更好呢?如果没有数字小于0,您应该用“this[0]”初始化您的v。应该在某个特定范围内调用比较器吗?因为as is每次都引用这个未定义的[index]。修复了,我总是忘记函数级别的作用域。哦,现在@Ionut G.Stan会批评你和我一样错误的上下文参数,因为你的默认comparer Math.xxx将在全局范围内运行…这可能是真的,但是新的函数签名不需要作用域,因为它接受需要比较的两个对象。@HankH:传递null、Math或{}或任何要应用或调用的对象对结果没有影响。max不应该也不应该在内部引用它。作为一名C程序员,我需要强类型的问题。只是分享了我在上面代码中犯的一个jQuery错误,这花了我很长时间进行调试。jquery阵列在除iPad之外的所有设备上都能正常工作。我必须将数组转换为真正的本机数组才能工作。由于某种原因仅影响单个设备Math.max.applynull,$.makeArrayarray;我投了反对票,因为提出的方法会消耗堆栈帧中的内存,因此会在大型阵列上崩溃。在我的例子中,大约130000个数字就足以使NodeJ崩溃。不要像这样扩充内置原型。这不仅仅是与其他库的冲突;这也关系到浏览器本身将来提供.max或.min方法的潜力。完美现实的场景:你使用这个答案。2016年,ES7或ES8规范Array.max和Array.min。与此版本不同,它们处理字符串。您未来的同事尝试使用现在已经有很好的文档记录的native.max方法获取数组中按字母顺序排列的最新字符串,但神秘地得到了NaN。几个小时后,她找到了这段代码,运行了一个git怪罪,并诅咒了你的名字。然而,为什么有人要修饰Foo.staticMethod并引用它呢?这不是装饰师设计中的一个错误吗?当然,除非他们想要引用全局范围,并且想要保持独立于所使用的JavaScript引擎,例如Rhino。明确说明了哪些特定函数应该引用该值。实际上,该短语在规范中出现了125次。根据规范实现的Math.max不使用此选项。如果有人重写Math.max,使其确实使用了此选项,则他们已使其行为违反规范,您应该向他们扔尖锐的对象。您不应该对这种可能性进行编码,就像您不应该对有人将Math.max和Math.min替换为l的可能性进行编码一样


有人能解释一下这是怎么回事吗?这真是太愚蠢了。我的理解正确吗:arrayMax是一个函数,我们将某些东西绑定到其原型的属性上?这个apply.bind是什么?每个原型都有吗?你可以检查一下:注意:reduce是IE9支持的,看,我似乎不能在Chromium的当前版本中使用它。@JordanDillonChapian我同意,但是,将其扩展到一个范围函数,这将是同时获得最小值和最大值的最佳方法,这将是一件微不足道的事情,正如我在更新我的答案时所做的那样。注意:使用ECMAScript 6,您可以使用新的三个点:。。。像这样使用Math.max:Math.max.[2,5,16,1]。请参阅。这里是最常用的速度比较方法的基准:在ES6中没有ES6 Math.max.applynull,[2,5,16,1],可以同时获得最大值和最小值。Math.max.applyMath,array和Math.max.applynull,array之间的区别是什么?博客上说…你还必须重复地说max属于Math…,但我似乎不必通过将apply的第一个参数设置为null来实现这一点。@ziyung当你像Math一样调用它时。maxa,b,Math作为this值传递,所以用apply调用时也可以这样做。但是Math.max不使用这个值,所以您可以传递任何您想要的值@然后你需要特别检查数组是否为空并返回+/-InfinityStrage。。。我去了链接的网站。。。在Firefox 51.0.0/Mac OS X 10.12.0中测试,基于reduce的方法比基于循环的方法慢30%。。。如果数组大小大于60,则从60个元素开始的非常不同的结果数学方法将以while循环打破相等,而数学方法将获胜。数组越大,数学方法的覆盖范围就越大。对于100个元素,Math.min/max速度快10%,对于1000个元素,2019年的reduce解决方案速度慢25%。即使使用具有数百万个元素的数组,也最好使用循环的标准。您在奖金中的最后一个示例将由大多数编程人员使用concat编写,因为它允许您保持单行样式。您的ES6示例,是否有任何理由不只是返回Math.max…array?@WojciechBednarski似乎建议使用spread运算符与传递要应用的数组相同,因此,最大参数限制也有同样的缺点。谢谢。只需更正reduce后缺少的括号:函数arrayMaxarray{return array.reducefunctiona,b{return Math.maxa,b;};//@DanielDietrich我猜做等效操作,调用Math.min不带值,返回无穷大,因此这些函数可以使用reduce…,Infinity来匹配该行为。我更喜欢它像当前一样抛出异常,因为取空数组的最小值似乎是一个错误。到目前为止reduce是最慢的。谢谢。我更改了答案。迭代仍然错误地访问不存在的属性。有什么问题,我没有看到任何错误。您能提供一个示例吗?现在进行相应修改。希望我正确理解您的意思。此解决方案已由answers.Math.max..[]提供=-Infinity。哈哈哈,是的,我的意思是javascript规范很糟糕。似乎很明显,没有数字的最小值是无法计算的。在其他更严肃的编程语言中,如Scala,要求空数组的最小值会引发一个异常。Scala是为那些需要机器来告诉他们他们做错了的人设计的,这…意味着什么?生活和学习…A.reducemin,val=>Math.minmin,val,A[0];即使是较短的问题也是一个额外的问题,即如何不仅返回最小值,而且返回其在数组中的位置?如果使用typescript,则所示的排列运算符将编译为Math.max.applyMath,arr以实现“max”兼容性。同样来自MDN:如果数组中的元素太多,排列…和应用都将失败或返回错误的结果 [...]reduce解决方案在测试Chrome、FF、Edge和IE11时没有这个问题。对于一个高达100k值的数组来说似乎还可以。在Win10和最新浏览器上测试:Chrome 110k、Firefox 300k、Edge 400k、IE11 150k。这是一个非常慢的方法,如果数组有数千个元素呢?@Slavafomini扩展了答案,使其涵盖了所有元素包含数千个元素的数组。请注意数组是否为空-您将得到负无穷大,这可能不是您想要的。如果您希望得到0,可以使用[0]。concatarr或扩展语法[0,…arr]有没有办法在方法1中排除空值来代替“arr”?@hafizur rahman方法1无法处理大数!就像2一样。请尝试使用任何大于10的数组⁷ items-Array.fromArray1000000.Keys中已经提到了这种精确的方法,但不包括所有已删除的答案。您的未格式化答案不会添加任何内容。只需将数组分散。Math.min…arr。
function maxValue(arr) {
  return arr.reduce((max, val) => max > val ? max : val)
}
function maxValue(arr) {
  let max = arr[0];

  for (let val of arr) {
    if (val > max) {
      max = val;
    }
  }
  return 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] });
}
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 nums = [12, 67, 58, 30].sort((x, y) => 
x -  y)
let min_val = nums[0]
let max_val = nums[nums.length -1]
array.sort((a, b) => b - a)[0];
array.sort((a, b) => a - b)[0];