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

fir*_*ger 79 javascript arrays compare

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

var myArray = [
    {"ID": 1, "Cost": 200},
    {"ID": 2, "Cost": 1000},
    {"ID": 3, "Cost": 50},
    {"ID": 4, "Cost": 500}
]
Run Code Online (Sandbox Code Playgroud)

我想专门针对"成本",并获得最小值和最大值.我意识到我可以抓住成本值并将它们推送到javascript数组中,然后运行Fast JavaScript Max/Min.

但是,通过绕过中间的数组步骤并直接关闭对象属性(在本例中为"Cost"),有更简单的方法吗?

Tri*_*eid 135

reduce对于这样的东西很有用:在对象数组上执行聚合操作(如min,max,avg等),并返回一个结果:

myArray.reduce(function(prev, curr) {
    return prev.Cost < curr.Cost ? prev : curr;
});
Run Code Online (Sandbox Code Playgroud)

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

(prev, curr) => prev.Cost < curr.Cost ? prev : curr
Run Code Online (Sandbox Code Playgroud)

现在你可以说:

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

  • 我认为最好的答案.它没有修改数组,它的内容比"创建一个数组,调用数组方法对于这个简单的操作来说太过分"的答案要简洁得多. (11认同)
  • 只是想知道,当reduce检查数组的第一个元素时,`prev.Cost`会不会是不确定的?还是以0开头? (2认同)

Rob*_*b W 49

在这种情况下,最快的方法是循环遍历所有元素,并将其与最高/最低值进行比较,到目前为止.

(创建一个数组,调用数组方法对于这个简单的操作来说是过度的).

 // 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);
Run Code Online (Sandbox Code Playgroud)

  • 我唯一要改变的是设置最低和最高有点多余。我宁愿少循环一次并设置`lowest=highest=myArray[0]`,然后从1开始循环。 (2认同)
  • 这个答案很旧,在 ECMAScript 2015 (ES6) 发布之前。当时是对的,但现在[那个答案](/sf/answers/2229125461/)是一个更好的选择。 (2认同)

kat*_*ugh 21

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

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

var min = myArray[0],
    max = myArray[myArray.length - 1]
Run Code Online (Sandbox Code Playgroud)

  • 请注意,这将修改`myArray`,这可能不是预期的. (4认同)
  • 对数组进行排序比遍历数组慢。排序复杂度:`O(nlog(n))`,遍历数组:`O(n)` (4认同)
  • 完全排序不是找到最小/最大的最快方法,但我想它会起作用. (3认同)

JuZ*_*che 14

使用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);
Run Code Online (Sandbox Code Playgroud)

  • 因为函数 `Math.max` 采用多个参数而不是数组。扩展运算符会将数组转换为参数“列表”。例如: `Math.max(...[1,5,9])` 相当于 `Math.max(1, 5, 9)`。如果没有扩展运算符,“Math.max(myArray)”将返回 NaN(不是数字),因为该函数需要多个数字参数。我希望现在回复@NtshemboHlongwane 还不算太晚;) (11认同)

J. *_*mes 13

我认为Rob W的回答确实是正确的(+1),但只是为了好玩:如果你想要"聪明",你可以这样做:

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

function finder(cmp, arr, attr) {
    var val = arr[0][attr];
    for(var i=1;i<arr.length;i++) {
        val = cmp(val, arr[i][attr])
    }
    return val;
}

alert(finder(Math.max, myArray, "Cost"));
alert(finder(Math.min, myArray, "Cost"));
Run Code Online (Sandbox Code Playgroud)

或者如果你有一个深层嵌套的结构,你可以获得更多功能,并执行以下操作:

var myArray = 
[
    {"ID": 1, "Cost": { "Wholesale":200, Retail: 250 }},
    {"ID": 2, "Cost": { "Wholesale":1000, Retail: 1010 }},
    {"ID": 3, "Cost": { "Wholesale":50, Retail: 300 }},
    {"ID": 4, "Cost": { "Wholesale":500, Retail: 1050 }}
]

function finder(cmp, arr, getter) {
    var val = getter(arr[0]);
    for(var i=1;i<arr.length;i++) {
        val = cmp(val, getter(arr[i]))
    }
    return val;
}

alert(finder(Math.max, myArray, function(x) { return x.Cost.Wholesale; }));
alert(finder(Math.min, myArray, function(x) { return x.Cost.Retail; }));
Run Code Online (Sandbox Code Playgroud)

这些可以很容易地变成更有用/特定的形式.

  • 我对我们的解决方案进行了基准测试:http://jsperf.com/comparison-of-numbers.优化代码后(参见基准测试),两种方法的性能相似.没有优化,我的方法快14倍. (4认同)
  • @RoBW哦,我完全希望你的版本更快*,我只是提供了另一种架构实现.:) (2认同)

Rup*_*ert 11

使用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
Run Code Online (Sandbox Code Playgroud)

更新:

如果你想使用ES6:

var min = Math.min.apply(null, myArray.map(item => item.Cost)),
    max = Math.max.apply(null, myArray.map(item => item.Cost));
Run Code Online (Sandbox Code Playgroud)

  • 在使用Spread Operator的ES6中,我们不再需要`apply`.简单地说 - `Math.min(... myArray.map(o => o.Cost))`用于查找最小值和`Math.max(... myArray.map(o => o.Cost))`找到最大值. (8认同)

Kam*_*ski 10

尝试(a是数组,f是要比较的字段)

let max= (a,f)=> a.reduce((m,x)=> m[f]>x[f] ? m:x);
let min= (a,f)=> a.reduce((m,x)=> m[f]<x[f] ? m:x);
Run Code Online (Sandbox Code Playgroud)

let max= (a,f)=> a.reduce((m,x)=> m[f]>x[f] ? m:x);
let min= (a,f)=> a.reduce((m,x)=> m[f]<x[f] ? m:x);
Run Code Online (Sandbox Code Playgroud)

  • 喜欢这个答案,如此紧凑且易于使用。 (3认同)

Tre*_*ent 7

这可以通过 lodashminBymaxBy函数来实现。

LodashminBymaxBy文档

_.minBy(array, [iteratee=_.identity])

_.maxBy(array, [iteratee=_.identity])

这些方法接受一个迭代器,为数组中的每个元素调用该迭代器来生成对值进行排名的标准。迭代器通过一个参数调用:(值)。

解决方案

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

const minimumCostItem = _.minBy(myArray, "Cost");

console.log("Minimum cost item: ", minimumCostItem);

// Getting the maximum using a functional iteratee
const maximumCostItem = _.maxBy(myArray, function(entry) {
  return entry["Cost"];
});

console.log("Maximum cost item: ", maximumCostItem);
Run Code Online (Sandbox Code Playgroud)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.js"></script>
Run Code Online (Sandbox Code Playgroud)


Iss*_*afi 6

最大

Math.max.apply(Math, myArray.map(a => a.Cost));
Run Code Online (Sandbox Code Playgroud)

分钟

Math.min.apply(Math, myArray.map(a => a.Cost));
Run Code Online (Sandbox Code Playgroud)


Mr.*_*irl 5

使用Array.prototype.reduce(),您可以插入比较器函数来确定数组中的最小值、最大值等。

var items = [
  { name : 'Apple',  count : 3  },
  { name : 'Banana', count : 10 },
  { name : 'Orange', count : 2  },
  { name : 'Mango',  count : 8  }
];

function findBy(arr, key, comparatorFn) {
  return arr.reduce(function(prev, curr, index, arr) { 
    return comparatorFn.call(arr, prev[key], curr[key]) ? prev : curr; 
  });
}

function minComp(prev, curr) {
  return prev < curr;
}

function maxComp(prev, curr) {
  return prev > curr;
}

document.body.innerHTML  = 'Min: ' + findBy(items, 'count', minComp).name + '<br />';
document.body.innerHTML += 'Max: ' + findBy(items, 'count', maxComp).name;
Run Code Online (Sandbox Code Playgroud)


hev*_*ev1 5

对于一种简洁、现代的解决方案,可以对reduce数组执行操作,跟踪当前的最小值和最大值,因此数组仅迭代一次(这是最佳的)。

let [min, max] = myArray.reduce(([prevMin,prevMax], {Cost})=>
   [Math.min(prevMin, Cost), Math.max(prevMax, Cost)], [Infinity, -Infinity]);
Run Code Online (Sandbox Code Playgroud)

演示:

let [min, max] = myArray.reduce(([prevMin,prevMax], {Cost})=>
   [Math.min(prevMin, Cost), Math.max(prevMax, Cost)], [Infinity, -Infinity]);
Run Code Online (Sandbox Code Playgroud)