【问题标题】:Get max and min of object values from JavaScript array从 JavaScript 数组中获取对象值的最大值和最小值
【发布时间】:2013-09-14 05:16:16
【问题描述】:

从 JavaScript 对象数组中获取最大值和最小值的最佳方法是什么?

给定:

var a = [{x:1,y:0},{x:-1,y:10},{x:12,y:20},{x:61,y:10}];
var minX = Infinity, maxX = -Infinity;
for( var x in a ){
  if( minX > a[x].x )
     minX = a[x].x;
  if( maxX < a[x].x )
     maxX = a[x].x;
}

看起来有点笨拙。有没有更优雅的方式,或许使用dojo?

【问题讨论】:

标签: javascript performance dojo


【解决方案1】:

它不会更有效率,但只是为了笑:

var minX = Math.min.apply(Math, a.map(function(val) { return val.x; }));
var maxX = Math.max.apply(Math, a.map(function(val) { return val.x; }));

或者如果你愿意拥有三行代码:

var xVals = a.map(function(val) { return val.x; });
var minX  = Math.min.apply(Math, xVals);
var maxX  = Math.max.apply(Math, xVals);

【讨论】:

  • 不错的一个:) 我认为Math.max/min 不接受两个以上的参数。
  • @wared 虽然遗憾的是,它是最慢的 :)
  • 很遗憾,考虑到你的诚实,我不能说这个测试是被操纵的:D
  • 我现在知道 apply 的作用了。谢谢。
  • 一个 ES6 方法是:const xVals = a.map((val) =&gt; val.x); const minValue = Math.min(...xVals); const maxValue = Math.max(...xVals);
【解决方案2】:

使用这个例子

var lowest = Number.POSITIVE_INFINITY;
var highest = Number.NEGATIVE_INFINITY;
var tmp;
for (var i=myArray.length-1; i>=0; i--) {
    tmp = myArray[i].Cost;
    if (tmp < lowest) lowest = tmp;
    if (tmp > highest) highest = tmp;
}
console.log(highest, lowest);

【讨论】:

  • 这不仅原则上与问题相同,而且实际上效率较低。不需要那个额外的变量。
  • 你说的是tmp吗?它更有效,因为它避免了重复查找。绝对需要这个变量。
  • @Brad - 除非我把 jsPerf test case 弄错了,否则这实际上比使用数组索引而不是 for/in 循环的 OP 算法版本要快得多。
  • 啊,我明白了!我根本没有注意。对于投反对票,我深表歉意。
  • 您仍然可以通过使用常量整数而不是混合整数和双精度数以及向前循环jsperf.com/creative-min-max/5 来将速度提高 35%。注意这个jsperf一般是坏的,所有的代码都应该被提取到非重复的函数中,并且这些函数在开始计时之前要适当地预热。
【解决方案3】:

您可以使用sort。此方法修改了原始数组,因此您可能需要克隆它:

var b = [].concat(a); // clones "a"
b.sort(function (a, b) { return a.x - b.x; });
var min = b[0];
var max = b[b.length - 1];

【讨论】:

  • 效率较低。 sort() 是 nlogn,比 OP 发布的 O(n) 慢。
  • @sza 在这种情况下,看起来 OP 使用的数组上的 for-in 循环比排序方法慢,这也让我感到惊讶。
  • @dc5 因为元素的数量。性能通常基于效率如何随着元件数量的增加而下降。尝试使用 1000 多个对象。
  • @sza - 我做了并且我理解了这些数字,我应该更清楚的是,即使有复制和回调的开销,它仍然更快,即使在较小的尺寸。
【解决方案4】:

我知道这有点太晚了,但对于新用户,您可以使用lodash。它使事情变得简单得多。

var a = [{x:1,y:0},{x:-1,y:10},{x:12,y:20},{x:61,y:10}];

var X = [];
var Y = [];
a.map(function (val) {
    X.push(val.x);
    Y.push(val.y);
});

var minX = _.min(X);
var minY = _.min(Y);
var maxX = _.max(X);
var maxY = _.max(Y);

或者你可以使用.sort() 来完成拖延者解释的任务。

【讨论】:

    【解决方案5】:

    另一个想法是通过将值减少到一个值来计算最大值/最小值。就时间复杂度而言,这与您的版本完全相同,但思考方式略有不同。 (自 JavaScript 1.8 起支持reduce()。)

    var getMax = function (field) {
        return a.reduce(function (acc, c) {
            return Math.max(c[field], acc);
        }, -Infinity);
    }
    
    var getMin = function (field) {
        return a.reduce(function (acc, c) {
            return Math.min(c[field], acc);
        }, Infinity);
    }
    
    console.log(getMax('x')) //61
    console.log(getMin('x')) //-1
    console.log(getMax('y')) //20
    console.log(getMin('y')) //0
    

    【讨论】:

    • 不需要acc = 部分,只需执行return Math.max(c[field], acc);
    • @Pumbaa80 谢谢。已更新。
    【解决方案6】:

    您可以使用map 功能,但它几乎只是for 周围的语法糖。任何使用reduce 的解决方案都将比您的“天真”慢两倍,因为它会为最小值迭代数组一次,为最大值迭代一次。就性能而言,您当前的解决方案几乎是您可以拥有的最佳解决方案。您所能做的就是通过缓存来减少更多查找。

    【讨论】:

    • @sza 的 reduce 版本的变体(更多的苹果到苹果)实际上比 OP 的 for/in 循环稍快:jsPerf results
    • @user123444555621 OP 确实提到了“优雅”,但也标记了问题 [性能]。
    猜你喜欢
    • 1970-01-01
    • 2012-02-10
    • 2023-02-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-23
    • 2011-08-16
    相关资源
    最近更新 更多