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

2020/09/20 19:31 · javascript ·  · 0评论

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

伪代码示例:

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

使用传播算子(ES6)

Math.max(...array);  // the same with "min" => Math.min(...array);

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

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

数组的最大大小

根据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针对不同解决方案的基准测试结果,以查找数组的最小/最大项

基准源代码

如果您像我一样使用偏执狂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给它的函数,而且传递i给数组本身的引用,因此我们必须确保我们也不要尝试调用max它们。

.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

奖金:

价差操作,您可以使用数组文本语法在ES5中,你将需要回落到必要的代码的情况下创建新的阵列,使用的组合pushsplice等等。

let foo = ['b', 'c'];
let bar = ['a', ...foo, 'd', 'e']; // ['a', 'b', 'c', 'd', 'e']

两种方法更短,更容易:

let arr = [2, 6, 1, 0]

方式1

let max = Math.max.apply(null, arr)

方式二

let max = arr.reduce(function(a, b) {
    return Math.max(a, b);
});

您可以通过扩展Array类型来做到这一点:

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

这里提升(由John Resig提供)

找到一个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]);

设置minA[0],然后检查A[1]...A[n]是否严格小于当前值min如果A[i] < min随后min更新为A[i]处理min所有数组元素后,返回结果。

编辑:包括最小值的位置:

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 }

Alternative Methods


The Math.min and Math.max methods are both recursive operations that being added to the JS engine's call stack, and most likely crash for an array that contains large number of items
(more than ~10⁷ items, depends on the user's browser).

Math.max(...Array(1000000).keys());

Uncaught RangeError: Maximum call stack size exceeded

Instead, use something like so:

arr.reduce((max, val) => max > val ? max : val, arr[0])

Or with better run-time:

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

  for (let val of arr) {
    if (val > max) {
      max = val;
    }
  }
  return max;
}

Or to get both Min and 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 };
}

*经过1,000,000项测试:

仅供参考,第一个函数运行时(在我的机器上)为15.84ms,而第二个函数运行时仅为4.32ms。

其他人已经给出了一些扩展解决方案Array.prototype所有我想要在这个答案是明确是否应该Math.min.apply( Math, array )还是Math.min.apply( null, array )那么什么情况下应该使用,Mathnull

null作为上下文传递给时apply,上下文将默认为全局对象(对于window浏览器对象)。Math对象作为上下文传递将是正确的解决方案,但也不会伤害传递null任何一个。这是null装饰Math.max函数可能引起麻烦的示例

// 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如果我们替换nullMath,如预期和字符串“foo”将被打印在屏幕上的东西就可以了(我测试了这个使用Mozilla的犀牛)。

您几乎可以假设没有人装饰过Math.max,传递null将毫无问题。

另一种方法是:

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

用法:

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

这可能适合您的目的。

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

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

这对我有用。

我很惊讶没有人提到减少功能。

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个元素),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;
};

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

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

您可以在项目中的任何地方使用以下功能:

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

反复进行,随时随地进行跟踪。

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

I thought I'd share my simple and easy to understand solution.

For the min:

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

And for the max:

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

简单的东西,真的。

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

这是一种从对象数组中获取最大值的方法。创建一个副本(带有切片),然后按降序对副本进行排序并获取第一项。

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; 

使用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

除了使用数学函数max和min之外,另一个要使用的函数是sort()的内置函数:

const nums = [12, 67, 58, 30].sort((x, y) => 
x -  y)
let max = nums[0]
let min = nums[nums.length -1]

如果您使用的是原型,ChaosPandion的解决方案就可以使用。如果没有,请考虑以下问题:

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

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

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

如果使用库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 }
array.sort((a, b) => b - a)[0];

在数字数组中为您提供最大值。

array.sort((a, b) => a - b)[0];

在数字数组中为您提供最小值。

let array = [0,20,45,85,41,5,7,85,90,111];

let maximum = array.sort((a, b) => b - a)[0];
let minimum = array.sort((a, b) => a - b)[0];

console.log(minimum, maximum)
let arr = [2,5,3,5,6,7,1];

let max = Math.max(...arr); // 7
let min = Math.min(...arr); // 1
本文地址:http://javascript.askforanswer.com/zaijavascriptzhongzhaodaoshuzudezuixiao-zuidayuansu.html
文章标签:
版权声明:本文为原创文章,版权归 javascript 所有,欢迎分享本文,转载请保留出处!

文件下载

老薛主机终身7折优惠码boke112

上一篇:
下一篇:

评论已关闭!