0

I have a JSON where I need to get the single maximum value of the maximum number. The below code displays maximum of each item, but I need to get the Max out of all the items. Here the expected answer is 78

for(var x in items) {
  console.log("Max is" + Math.Max(items[x]));
}


var items = {
    "title": "Find Max",
    "A": [0, 78],
    "Z": [1],
    "R": [2, 10],
    "N": [2, 10, 56],
    "P": [5, 56]
}
2
  • what is expected output ? Commented May 14, 2020 at 4:17
  • 78 is the expected output Commented May 14, 2020 at 4:25

3 Answers 3

3

You can use Object.values to get the values of each property of your object; filter those values to only return the arrays (using Array.isArray), and then use Array.reduce to find the maximum value over all the arrays:

var items = {
  "title": "Find Max",
  "A": [0, 78],
  "Z": [1],
  "R": [2, 10],
  "N": [2, 10, 56],
  "P": [5, 56]
}
const max = Object.values(items).filter(v => Array.isArray(v)).reduce((c, v) => Math.max(c, ...v), Number.MIN_SAFE_INTEGER);
console.log(max);

This can be written without the filter by incorporating the logic into the reduce:

var items = {
  "title": "Find Max",
  "A": [0, 78],
  "Z": [1],
  "R": [2, 10],
  "N": [2, 10, 56],
  "P": [5, 56]
}
const max = Object.values(items).reduce((c, v) => Array.isArray(v) ? Math.max(c, ...v) : c, Number.MIN_SAFE_INTEGER);
console.log(max);

If you can't use ES6 arrow functions, this will work:

var items = {
  "title": "Find Max",
  "A": [0, 78],
  "Z": [1],
  "R": [2, 10],
  "N": [2, 10, 56],
  "P": [5, 56]
}
const max = Object.values(items).filter(function(v) {
  return Array.isArray(v);
}).reduce(function(c, v) {
  return Math.max(c, ...v);
}, Number.MIN_SAFE_INTEGER);
console.log(max);

If the spread operator is also unavailable, you can use Array.reduce again to get the maximum value from the array:

var items = {
  "title": "Find Max",
  "A": [0, 78],
  "Z": [1],
  "R": [2, 10],
  "N": [2, 10, 56],
  "P": [5, 56]
}
const max = Object.values(items).filter(function(v) {
  return Array.isArray(v);
}).reduce(function(c, v) {
  return v.reduce(function(a, b) {
    return Math.max(a, b);
  }, c);
}, Number.MIN_SAFE_INTEGER);
console.log(max);

Sign up to request clarification or add additional context in comments.

7 Comments

=> is not allowed, could you help me without => operator?
@CodeGuy I've edited my answer with a solution which doesn't use arrow functions
@Nick if arrow functions aren't valid, then spread syntax probably isn't either. You'll need Function.prototype.apply()
@Phil have edited in a solution which doesn't use spread either. But it seems that wasn't the problem with arrow functions.
strange algorithm, why filter followed by reduce when reduce is more generic? why Math.max(c, Math.max(...v)) which is the same as Math.max(c, ...v)?
|
2

I think you'll enjoy the simplicity and efficiency of this algorithm -

const items = {
  "title": "Find Max",
  "A": [0, 78],
  "Z": [1],
  "R": [2, 10],
  "N": [2, 10, 56],
  "P": [5, 56]
}

const nums =
  Object.values(items).flatMap(function (x) {
    if (Array.isArray(x))
      return x
    else
      return []
  })
  
const result =
  Math.max(-Infinity, ...nums)

console.log(result)
// 78

If items does not contain any numbers, the result will be -Infinity


generators

Here's another interesting approach using generators, if they are allowed. I think generators are particularly useful in this situation because input is a complex object. items is nested and some of the values we need to compare are non-numeric. It'd be nice we had a values function that could produce a stream of all nested values -

const values = function* (t)
{ if (Array.isArray(t))
    for (const v of t)
      yield* values(v)
  else if (Object(t) === t)
    for (const v of Object.values(t))
      yield* values(v)
  else
    yield t
}

const items = {
  "title": "Find Max",
  "A": [0, 78],
  "Z": [1],
  "R": [2, 10],
  "N": [2, 10, 56],
  "P": [5, 56]
}

let r = -Infinity
for (const v of values(items))
  if (Number(v) === v)
    r = Math.max(r, v)
console.log(r)
// 78

Generators return an iterator. An iterator gives us one value and will not compute the next one until we ask for it. Generators are called "lazy" because of this. Note we can use for..of to iterate through a generator, exactly as we do with arrays.

But if you use this technique, don't stop here. Even though generators do not return arrays, we can write code that allows us to conceptualise the two similarly.

We could write general functions like filter to select values matching a predicate, eg isNumber -

const isNumber = function(x)
{ return Number(x) === x
}

const filter = function* (test, t)
{ for (const v of t)
    if (test(v))
      yield v
}

for (const v of filter(isNumber, values(items)))
  console.log(v)

0
78
1
2
10
2
10
56
5
56

And we could write reduce -

const reduce = function(f, init, t)
{ let r = init
  for (const v of t)
    r = f(r, v)
  return r
}

const result =
  reduce
    ( Math.max
    , -Infinity
    , filter(isNumber, values(items))
    )

console.log(result)
// 78

Run the snippet below to verify the results in your own browser -

const values = function* (t)
{ if (Array.isArray(t))
    for (const v of t)
      yield* values(v)
  else if (Object(t) === t)
    for (const v of Object.values(t))
      yield* values(v)
  else
    yield t
}

const filter = function* (test, t)
{ for (const v of t)
    if (test(v))
      yield v
}
 
const reduce = function(f, init, t)
{ let r = init
  for (const v of t)
    r = f(r, v)
  return r
}

const isNumber = function(x)
{ return Number(x) === x
}

const items = {
  "title": "Find Max",
  "A": [0, 78],
  "Z": [1],
  "R": [2, 10],
  "N": [2, 10, 56],
  "P": [5, 56]
}
  
const result =
  reduce
    ( Math.max
    , -Infinity
    , filter(isNumber, values(items))
    )

console.log(result)
// 78

Comments

1

A little less complex code for newbies:

var items = {
  "title": "Find Max",
  "A": [0, 78],
  "Z": [1],
  "R": [2, 10],
  "N": [2, 10, 56],
  "P": [5, 56]
}

let array = [];

for (const property in items) {
  if (Array.isArray(items[property])) {
    let newArray = items[property];
    array = [...array, ...newArray]
  }
}

console.log(Math.max(...array)) // 78

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.