Compare JavaScript Array of Objects to Get Min / Max

JavascriptArraysCompare

Javascript Problem Overview


I have an array of objects and I want to compare those objects on a specific object property. Here's my array:

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

I'd like to zero in on the "cost" specifically and a get a min and maximum value. I realize I can just grab the cost values and push them off into a javascript array and then run the [Fast JavaScript Max/Min][1].

However is there an easier way to do this by bypassing the array step in the middle and going off the objects properties (in this case "Cost") directly?

[1]: http://ejohn.org/blog/fast-javascript-maxmin/ "Fast JavaScript Max/Min"

Javascript Solutions


Solution 1 - Javascript

The reduce is good for stuff like this: to perform aggregate operations (like min, max, avg, etc.) on an array of objects, and return a single result:

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

...or you can define that inner function with ES6 function syntax:

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

If you want to be cute you can attach this to array:

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

Now you can just say:

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

Please note that if you intend to use this, it doesn't have full checks for every situation. If you pass in an array of primitive types, it will fail. If you check for a property that doesn't exist, or if not all the objects contain that property, you will get the last element. This version is a little more bulky, but has those checks:

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

Solution 2 - Javascript

One way is to loop through all elements and compare it to the highest/lowest value.

(Creating an array, invoking array methods is overkill for this simple operation).

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

Solution 3 - Javascript

Use sort, if you don't care about the array being modified.

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

var min = myArray[0],
    max = myArray[myArray.length - 1]

Solution 4 - Javascript

Use Math functions and pluck out the values you want with map.

Here is the 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

UPDATE:

If you want to use ES6:

var min = Math.min.apply(null, myArray.map(item => item.Cost)),
    max = Math.max.apply(null, myArray.map(item => item.Cost));

Solution 5 - Javascript

Using Math.min and Math.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);

Solution 6 - Javascript

I think Rob W's answer is really the right one (+1), but just for fun: if you wanted to be "clever", you could do something like this:

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

or if you had a deeply nested structure, you could get a little more functional and do the following:

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

These could easily be curried into more useful/specific forms.

Solution 7 - Javascript

Try (a is array, f is field to compare)

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

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

// TEST

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

console.log('Max Cost', max(myArray, 'Cost'));
console.log('Min Cost', min(myArray, 'Cost'));

console.log('Max ID', max(myArray, 'ID'));
console.log('Min ID', min(myArray, 'ID'));

Solution 8 - Javascript

for Max

Math.max.apply(Math, myArray.map(a => a.Cost));

for min

Math.min.apply(Math, myArray.map(a => a.Cost));

Solution 9 - Javascript

This can be achieved with lodash's minBy and maxBy functions.

Lodash's minBy and maxBy documentation > _.minBy(array, [iteratee=_.identity])

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

> These methods accept an iteratee which is invoked for each element in > array to generate the criterion by which the value is ranked. The > iteratee is invoked with one argument: (value).

Solution

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

<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.js"></script>

Solution 10 - Javascript

Using Array.prototype.reduce(), you can plug in comparator functions to determine the min, max, etc. item in an array.

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;

Solution 11 - Javascript

This is more better solution

    var myArray = [
    {"ID": 1, "Cost": 200},
    {"ID": 2, "Cost": 1000},
    {"ID": 3, "Cost": 50},
    {"ID": 4, "Cost": 500}
    ]
    var lowestNumber = myArray[0].Cost;
    var highestNumber = myArray[0].Cost;
    
    myArray.forEach(function (keyValue, index, myArray) {
      if(index > 0) {
        if(keyValue.Cost < lowestNumber){
          lowestNumber = keyValue.Cost;
        }
        if(keyValue.Cost > highestNumber) {
          highestNumber = keyValue.Cost;
        }
      }
    });
    console.log('lowest number' , lowestNumber);
    console.log('highest Number' , highestNumber);

Solution 12 - Javascript

Adding onto Tristan Reid's answer (+ using es6), you could create a function that accepts a callback, which will contain the operator you want to be applied to the prev and curr:

const compare = (arr, key, callback) => arr.reduce((prev, curr) =>
    (callback(prev[key], curr[key]) ? prev : curr), {})[key];

    // remove `[key]` to return the whole object

Then you could simply call it using:

const costMin = compare(myArray, 'Cost', (a, b) => a < b);
const costMax = compare(myArray, 'Cost', (a, b) => a > b);

Solution 13 - Javascript

For a concise, modern solution, one can perform a reduce operation over the array, keeping track of the current minimum and maximum values, so the array is only iterated over once (which is optimal).

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

Demo:

var myArray = [
    {"ID": 1, "Cost": 200},
    {"ID": 2, "Cost": 1000},
    {"ID": 3, "Cost": 50},
    {"ID": 4, "Cost": 500}
]
let [min, max] = myArray.reduce(([prevMin,prevMax], {Cost})=>
   [Math.min(prevMin, Cost), Math.max(prevMax, Cost)], [Infinity, -Infinity]);
console.log("Min cost:", min);
console.log("Max cost:", max);

Solution 14 - Javascript

> we can solve problem by two approach both method is already explained above but the performance test was missing so completing that one

1, native java-script way
2, first sort object then it easy to get min max from sorted obj

> i also test performance of both tow approach
> > you can also run and test performance... Happy coding (:

//first approach 

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

var t1 = performance.now();;

let max=Math.max.apply(Math, myArray.map(i=>i.Cost))

let min=Math.min.apply(Math, myArray.map(i=>i.Cost))

var t2   = performance.now();;

console.log("native fuction took " + (t2 - t1) + " milliseconds.");

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

//  Second approach:


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

var s1 = performance.now();;
sortedArray=myArray.sort(sortFunc)


var minBySortArray = sortedArray[0],
    maxBySortArray = sortedArray[myArray.length - 1]
    
var s2   = performance.now();;
 console.log("sort funciton took  " + (s2 - s1) + " milliseconds.");  
console.log("max ValBySortArray :"+max)
console.log("min Val BySortArray:"+min)

Solution 15 - Javascript

max = totalAVG.reduce(function (a, b) { return Math.max(a, b)}, -Infinity);

min = totalAVG.reduce(function (a, b) {return Math.min(a, b)}, Infinity);

Solution 16 - Javascript

Another one, similar to Kennebec's answer, but all in one line:

maxsort = myArray.slice(0).sort(function (a, b) { return b.ID - a.ID })[0].ID; 

Solution 17 - Javascript

You can use built-in Array object to use Math.max/Math.min instead:

var arr = [1,4,2,6,88,22,344];

var max = Math.max.apply(Math, arr);// return 344
var min = Math.min.apply(Math, arr);// return 1

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionfiredrawndaggerView Question on Stackoverflow
Solution 1 - JavascriptTristan ReidView Answer on Stackoverflow
Solution 2 - JavascriptRob WView Answer on Stackoverflow
Solution 3 - JavascriptkatspaughView Answer on Stackoverflow
Solution 4 - JavascriptRupertView Answer on Stackoverflow
Solution 5 - JavascriptJuZDePecheView Answer on Stackoverflow
Solution 6 - JavascriptJ. HolmesView Answer on Stackoverflow
Solution 7 - JavascriptKamil KiełczewskiView Answer on Stackoverflow
Solution 8 - JavascriptIssa LafiView Answer on Stackoverflow
Solution 9 - JavascriptTrentView Answer on Stackoverflow
Solution 10 - JavascriptMr. PolywhirlView Answer on Stackoverflow
Solution 11 - JavascriptDeepak SisodiyaView Answer on Stackoverflow
Solution 12 - JavascriptJames MoranView Answer on Stackoverflow
Solution 13 - JavascriptUnmitigatedView Answer on Stackoverflow
Solution 14 - JavascriptJadliView Answer on Stackoverflow
Solution 15 - JavascriptDARSHIL SAKHIYAView Answer on Stackoverflow
Solution 16 - JavascriptBenView Answer on Stackoverflow
Solution 17 - JavascriptsourcecodeView Answer on Stackoverflow