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

如何轻松获得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.minMath.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 )那么应该使用什么上下文, Mathnull

当将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.fooundefined 。 如果我们将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楼

我遇到了同样的问题,我需要获取数组的最小值和最大值,令我惊讶的是,没有用于数组的内置函数。 看了很多书后,我决定自己测试“前三名”解决方案:

  1. 离散解决方案:一个FOR循环,根据当前的最大值和/或最小值检查数组的每个元素;
  2. APPLY解决方案:使用apply(null,array)将数组发送到Math.max和/或Math.min内部函数;
  3. 减少解决方案:使用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个小数位数和标准偏差:

  1. 离散解:平均值= 0.161s,sd = 0.078
  2. 应用解决方案:平均值= 3.571s,标准差= 0.487
  3. 减少求解:均值= 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-Dashunderscore.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退回到命令性代码的情况下使用pushsplice等组合来创建新数组。

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

数组的最大大小

据MDNapply和传播解决方案提供从参数的最大数目的限制来了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基准

jsperf.com针对不同解决方案的基准测试结果,以查找数组的最小/最大项

JSBen基准

jsben.com针对不同解决方案的基准测试结果,以查找数组的最小/最大项

JSBench.me基准

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不仅将ab传递给函数,而且还传递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] < minmin更新为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.minMath.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.minMath.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原型框架

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值