比较 JavaScript 对象数组以获取最小值/最大值

IT技术 javascript arrays compare
2021-02-10 18:56:46

我有一个对象数组,我想在特定对象属性上比较这些对象。这是我的数组:

var myArray = [
    {"ID": 1, "Cost": 200},
    {"ID": 2, "Cost": 1000},
    {"ID": 3, "Cost": 50},
    {"ID": 4, "Cost": 500}
]

我想特别将“成本”归零并获得最小值和最大值。我意识到我可以获取成本值并将它们推送到 javascript 数组中,然后运行Fast JavaScript Max/Min

但是,是否有一种更简单的方法可以通过绕过中间的数组步骤并直接关闭对象属性(在本例中为“成本”)?

6个回答

reduce 适合这样的事情:在对象数组上执行聚合操作(如 min、max、avg 等),并返回单个结果:

myArray.reduce(function(prev, curr) {
    return prev.Cost < curr.Cost ? prev : curr;
});

...或者您可以使用 ES6 函数语法定义该内部函数:

(prev, curr) => prev.Cost < curr.Cost ? prev : curr

如果你想变得可爱,你可以把它附加到数组:

Array.prototype.hasMin = function(attrib) {
    return (this.length && this.reduce(function(prev, curr){ 
        return prev[attrib] < curr[attrib] ? prev : curr; 
    })) || null;
 }

现在你可以说:

myArray.hasMin('ID')  // result:  {"ID": 1, "Cost": 200}
myArray.hasMin('Cost')    // result: {"ID": 3, "Cost": 50}
myEmptyArray.hasMin('ID')   // result: null

请注意,如果您打算使用它,它不会对每种情况进行全面检查。如果你传入一个原始类型的数组,它将失败。如果您检查不存在的属性,或者不是所有对象都包含该属性,您将获得最后一个元素。这个版本有点笨重,但有这些检查:

Array.prototype.hasMin = function(attrib) {
    const checker = (o, i) => typeof(o) === 'object' && o[i]
    return (this.length && this.reduce(function(prev, curr){
        const prevOk = checker(prev, attrib);
        const currOk = checker(curr, attrib);
        if (!prevOk && !currOk) return {};
        if (!prevOk) return curr;
        if (!currOk) return prev;
        return prev[attrib] < curr[attrib] ? prev : curr; 
    })) || null;
 }
好点@Saheb。我刚刚进行了编辑,因此在这种情况下它将返回 null。
2021-03-24 18:56:46
在我看来最好的答案。它不会修改数组,而且比“创建数组,调用数组方法对于这个简单的操作来说太过分了”的答案要简洁得多
2021-04-02 18:56:46
我还为可能导致问题的其他输入添加了一些检查,例如非对象,或者某些对象中是否缺少该属性。最终,在我认为的大多数情况下,它会变得有点严厉。
2021-04-02 18:56:46
只是想知道,当reduce 检查数组的第一个元素时,不会prev.Cost是未定义的?或者它启动为0?
2021-04-09 18:56:46
这是大型数据集(30 多列/10 万行)性能的绝对最佳答案。
2021-04-12 18:56:46

一种方法是遍历所有元素并将其与最高/最低值进行比较。

(创建一个数组,调用数组方法对于这个简单的操作来说太过分了)。

 // There's no real number bigger than plus Infinity
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);
这个答案很旧,在 ECMAScript 2015 (ES6) 出来之前。当时是对的,但现在这个答案是更好的选择。
2021-03-15 18:56:46
@32bitkid 好点。应该是myArray[0].Cost,不过。但是,如果没有第一个元素,则会抛出错误。因此,需要进行额外的检查,这可能会抵消小的性能提升。
2021-03-22 18:56:46
@Wilt是,保持当你发现了一个最低值,该值被更新另一个变量,即var lowestObject; for (...)if (tmp < lowest) { lowestObject = myArray[i]; lowest = tmp; }
2021-03-31 18:56:46
这是有道理的,我一直在考虑比较数组内的数据而不是外部高/低数字。
2021-04-03 18:56:46
我唯一要改变的是设置最低和最高有点多余。我宁愿少循环一次并设置lowest=highest=myArray[0]然后从 1 开始循环。
2021-04-12 18:56:46

使用sort,如果你不关心的阵列进行修改。

myArray.sort(function (a, b) {
    return a.Cost - b.Cost
})

var min = myArray[0],
    max = myArray[myArray.length - 1]
对数组进行排序比遍历它慢。排序复杂度:O(nlog(n)),遍历数组:O(n)
2021-03-15 18:56:46
完整排序不是找到最小值/最大值的最快方法,但我想它会起作用。
2021-03-18 18:56:46
请注意,这会修改myArray,这可能出乎意料。
2021-04-12 18:56:46

使用Math函数并用 提取出你想要的值map

这是jsbin:

https://jsbin.com/necosu/1/edit?js,console

var myArray = [{
    "ID": 1,
    "Cost": 200
  }, {
    "ID": 2,
    "Cost": 1000
  }, {
    "ID": 3,
    "Cost": 50
  }, {
    "ID": 4,
    "Cost": 500
  }],

  min = Math.min.apply(null, myArray.map(function(item) {
    return item.Cost;
  })),
  max = Math.max.apply(null, myArray.map(function(item) {
    return item.Cost;
  }));

console.log('min', min);//50
console.log('max', max);//1000

更新:

如果你想使用 ES6:

var min = Math.min.apply(null, myArray.map(item => item.Cost)),
    max = Math.max.apply(null, myArray.map(item => item.Cost));
在使用扩展运算符的 ES6 中,我们不再需要apply. 简单地说 - Math.min(...myArray.map(o => o.Cost))寻找最小值和 Math.max(...myArray.map(o => o.Cost))寻找最大值。
2021-04-12 18:56:46

使用Math.minMath.max

var myArray = [
    { id: 1, cost: 200},
    { id: 2, cost: 1000},
    { id: 3, cost: 50},
    { id: 4, cost: 500}
]


var min = Math.min(...myArray.map(item => item.cost));
var max = Math.max(...myArray.map(item => item.cost));

console.log("min: " + min);
console.log("max: " + max);

我知道现在问肯定为时已晚,但为什么我们需要像您一样的点差运算符,因为myArray.map()我很感激您的回答
2021-03-13 18:56:46
因为该函数Math.max需要多个参数而不是数组。展开运算符会将数组转换为参数“列表”。例如:Math.max(...[1,5,9])相当于Math.max(1, 5, 9). 如果没有扩展运算符,Math.max(myArray)将返回 NaN(不是数字),因为该函数需要多个数字参数。我希望现在回复@NtshemboHlongwane 还不晚;)
2021-04-02 18:56:46