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