129

I have an object in javascript like this:

{ "a":4, "b":0.5 , "c":0.35, "d":5 }

Is there a fast way to get the minimum and maximum value among the properties without having to loop through them all? because the object I have is huge and I need to get the min/max value every two seconds. (The values of the object keeps changing).

Y2theZ
  • 10,162
  • 38
  • 131
  • 200
  • 3
    @Oleg: Well, given only this, it could very well be JSON. Youssef: Parse the JSON into an object and iterate over its properties. – Felix Kling Jun 21 '12 at 16:48
  • @OlegV.Volkov I'm using JSON.parse() shouldn't that make it Json? – Y2theZ Jun 21 '12 at 16:49
  • @Youssef It was JSON (which is a String value) before parsing. It's an Object value after parsing. – Šime Vidas Jun 21 '12 at 16:50
  • 2
    JSON is the string notation of objects. When you parse JSON to an object, it's no longer in the JSON format – altschuler Jun 21 '12 at 16:50
  • @Youssef: The value you *pass* to `JSON.parse` is a string containing JSON. The result is an object. (maybe that's what you mean) – Felix Kling Jun 21 '12 at 16:50
  • @FelixKling I am trying to avoid iterating over the entire data because it is huge and it need to be done every 2 seconds. wont that affect performance? – Y2theZ Jun 21 '12 at 16:51
  • Does this mean every to seconds you get new JSON, containing all the data? – Felix Kling Jun 21 '12 at 16:52
  • no. I have the data and I do math operations on some of the fields every two seconds and then need to get the new min/max – Y2theZ Jun 21 '12 at 16:54
  • So you actually have an object with changing fields and you always want to know the min and max value. See carlosfigueira's answer. Your problem does not seems to be related to JSON at all btw. – Felix Kling Jun 21 '12 at 16:56
  • 1
    I took liberty of fixing JSON -> object in your question, as comments confirm that it is what you've meant. – Oleg V. Volkov Jun 21 '12 at 17:05
  • Updated my solution to make use of the fact that Objects retain their order in ES6: https://stackoverflow.com/a/53661894/4722345 – JBallin Mar 25 '19 at 00:21

16 Answers16

197

Update: Modern version (ES6+)

let obj = { a: 4, b: 0.5 , c: 0.35, d: 5 };

let arr = Object.values(obj);
let min = Math.min(...arr);
let max = Math.max(...arr);

console.log( `Min value: ${min}, max value: ${max}` );

Original Answer:

Try this:

let obj = { a: 4, b: 0.5 , c: 0.35, d: 5 };
var arr = Object.keys( obj ).map(function ( key ) { return obj[key]; });

and then:

var min = Math.min.apply( null, arr );
var max = Math.max.apply( null, arr );

Live demo: http://jsfiddle.net/7GCu7/1/

Community
  • 1
  • 1
Šime Vidas
  • 182,163
  • 62
  • 281
  • 385
23

There's no way to find the maximum / minimum in the general case without looping through all the n elements (if you go from, 1 to n-1, how do you know whether the element n isn't larger (or smaller) than the current max/min)?

You mentioned that the values change every couple of seconds. If you know exactly which values change, you can start with your previous max/min values, and only compare with the new ones, but even in this case, if one of the values which were modified was your old max/min, you may need to loop through them again.

Another alternative - again, only if the number of values which change are small - would be to store the values in a structure such as a tree or a heap, and as the new values arrive you'd insert (or update) them appropriately. But whether you can do that is not clear based on your question.

If you want to get the maximum / minimum element of a given list while looping through all elements, then you can use something like the snippet below, but you will not be able to do that without going through all of them

var list = { "a":4, "b":0.5 , "c":0.35, "d":5 };
var keys = Object.keys(list);
var min = list[keys[0]]; // ignoring case of empty list for conciseness
var max = list[keys[0]];
var i;

for (i = 1; i < keys.length; i++) {
    var value = list[keys[i]];
    if (value < min) min = value;
    if (value > max) max = value;
}
carlosfigueira
  • 85,035
  • 14
  • 131
  • 171
  • 2
    This does not describe how to get the min/max values of the properties of an object. – FistOfFury Apr 04 '20 at 00:50
  • You are iterating over an object, not a list. `min` and `max` are undefined. Did you mean to use a `for in` loop instead? – tonix Oct 26 '20 at 21:42
14

You could try:

const obj = { a: 4, b: 0.5 , c: 0.35, d: 5 };
const max = Math.max.apply(null, Object.values(obj));
console.log(max) // 5
Dave Kalu
  • 1,520
  • 3
  • 19
  • 38
12

min and max have to loop through the input array anyway - how else would they find the biggest or smallest element?

So just a quick for..in loop will work just fine.

var min = Infinity, max = -Infinity, x;
for( x in input) {
    if( input[x] < min) min = input[x];
    if( input[x] > max) max = input[x];
}
Niet the Dark Absol
  • 320,036
  • 81
  • 464
  • 592
  • 1
    This is great for IE7/8. Cheers @Niet the Dark Absol – ojhawkins Oct 27 '13 at 23:35
  • It's not necessarily true that min and max loop through the array to get their values. It's more feasible that they quicksort the array and select min and max values based on that result – goonerify Mar 16 '15 at 14:16
  • 8
    @goonerify The fastest sort is `O(n log n)`, which is inherently slower than the `O(n)` that just scanning through once would be... – Niet the Dark Absol Mar 16 '15 at 15:11
5
// 1. iterate through object values and get them
// 2. sort that array of values ascending or descending and take first, 
//    which is min or max accordingly
let obj = { 'a': 4, 'b': 0.5, 'c': 0.35, 'd': 5 }
let min = Object.values(obj).sort((prev, next) => prev - next)[0] // 0.35
let max = Object.values(obj).sort((prev, next) => next - prev)[0] // 5
Andrey Kudriavtsev
  • 1,124
  • 11
  • 19
4

You can also try with Object.values

const points = { Neel: 100, Veer: 89, Shubham: 78, Vikash: 67 };

const vals = Object.values(points);
const max = Math.max(...vals);
const min = Math.min(...vals);
console.log(max);
console.log(min);
Neel Rathod
  • 2,013
  • 12
  • 28
4
// Sorted
let Sorted = Object.entries({ "a":4, "b":0.5 , "c":0.35, "d":5 }).sort((prev, next) => prev[1] - next[1])
>> [ [ 'c', 0.35 ], [ 'b', 0.5 ], [ 'a', 4 ], [ 'd', 5 ] ]


//Min:
Sorted.shift()
>> [ 'c', 0.35 ]

// Max:
Sorted.pop()
>> [ 'd', 5 ]
Timothy Bushell
  • 170
  • 1
  • 7
4

You can use a reduce() function.

Example:

let obj = { "a": 4, "b": 0.5, "c": 0.35, "d": 5 }

let max = Object.entries(obj).reduce((max, entry) => entry[1] >= max[1] ? entry : max, [0, -Infinity])
let min = Object.entries(obj).reduce((min, entry) => entry[1] <= min[1] ? entry : min, [0, +Infinity])

console.log(max) // ["d", 5]
console.log(min) // ["c", 0.35]
Erik Martín Jordán
  • 4,332
  • 3
  • 26
  • 36
4

To get the keys for max and min

var list = { "a":4, "b":0.5 , "c":0.35, "d":5 };
var keys = Object.keys(list);
var min = keys[0]; // ignoring case of empty list for conciseness
var max = keys[0];
var i;

for (i = 1; i < keys.length; i++) {
    var value = keys[i];
    if (list[value] < list[min]) min = value;
    if (list[value] > list[max]) max = value;
}

console.log(min, '-----', max)
Hammed Noibi
  • 51
  • 1
  • 5
3

Here's a solution that allows you to return the key as well and only does one loop. It sorts the Object's entries (by val) and then returns the first and last one.

Additionally, it returns the sorted Object which can replace the existing Object so that future sorts will be faster because it will already be semi-sorted = better than O(n). It's important to note that Objects retain their order in ES6.

const maxMinVal = (obj) => {
  const sortedEntriesByVal = Object.entries(obj).sort(([, v1], [, v2]) => v1 - v2);

  return {
    min: sortedEntriesByVal[0],
    max: sortedEntriesByVal[sortedEntriesByVal.length - 1],
    sortedObjByVal: sortedEntriesByVal.reduce((r, [k, v]) => ({ ...r, [k]: v }), {}),
  };
};

const obj = {
  a: 4, b: 0.5, c: 0.35, d: 5
};

console.log(maxMinVal(obj));
JBallin
  • 8,481
  • 4
  • 46
  • 51
2

For nested structures of different depth, i.e. {node: {leaf: 4}, leaf: 1}, this will work (using lodash or underscore):

function getMaxValue(d){
    if(typeof d === "number") {
        return d;
    } else if(typeof d === "object") {
        return _.max(_.map(_.keys(d), function(key) {
            return getMaxValue(d[key]);
        }));
    } else {
        return false;
    }
}
user4815162342
  • 1,638
  • 2
  • 17
  • 23
2

Using the lodash library you can write shorter

_({ "a":4, "b":0.5 , "c":0.35, "d":5 }).values().max();
Sergey Zhigalov
  • 1,019
  • 8
  • 3
2
var newObj = { a: 4, b: 0.5 , c: 0.35, d: 5 };
var maxValue = Math.max(...Object.values(newObj))
var minValue = Math.min(...Object.values(newObj))
  • 3
    When answering an old question, your answer would be much more useful to other StackOverflow users if you included some context to explain how your answer helps, particularly for a question that already has an accepted answer. See: [How do I write a good answer](https://stackoverflow.com/help/how-to-answer). – David Buck Jan 16 '20 at 10:09
1
   obj.prototype.getMaxinObjArr = function (arr,propName) {
        var _arr = arr.map(obj => obj[propName]);
        return Math.max(..._arr);
    }
AHMED RABEE
  • 467
  • 6
  • 13
0

This works for me:

var object = { a: 4, b: 0.5 , c: 0.35, d: 5 };
// Take all value from the object into list
var valueList = $.map(object,function(v){
     return v;
});
var max = valueList.reduce(function(a, b) { return Math.max(a, b); });
var min = valueList.reduce(function(a, b) { return Math.min(a, b); });
lennyklb
  • 1,307
  • 2
  • 15
  • 32
jaydip jadhav
  • 477
  • 4
  • 5
0

If we are sorting date time value then follow the below described procedure

const Obj = {
    "TRADE::Trade1": {
        "dateTime": "2022-11-27T20:17:05.980Z",
    },
    "TRADE::Trade2": {
        "dateTime": "2022-11-27T20:36:10.659Z",
    },
    "TRADE::Trade3": {
        "dateTime": "2022-11-27T20:28:10.659Z",
    }
} 


const result = Object.entries(Obj).sort((prev, next) => new Date(prev[1].dateTime) - new Date(next[1].dateTime))

console.log(result)
KARTHIKEYAN.A
  • 18,210
  • 6
  • 124
  • 133