'Using reduce() to find min and max values?

I have this code for a class where I'm supposed to use the reduce() method to find the min and max values in an array. However, we are required to use only a single call to reduce. The return array should be of size 2, but I know that the reduce() method always returns an array of size 1.

I'm able to obtain the minimum value using the code below, however I don't know how to obtain the max value in that same call. I assume that once I do obtain the max value that I just push it to the array after the reduce() method finishes.

/**
 * Takes an array of numbers and returns an array of size 2,
 * where the first element is the smallest element in items,
 * and the second element is the largest element in items.
 *
 * Must do this by using a single call to reduce.
 *
 * For example, minMax([4, 1, 2, 7, 6]) returns [1, 7]
 */
function minMax(items) {
  var minMaxArray = items.reduce(
    (accumulator, currentValue) => {
      return (accumulator < currentValue ? accumulator : currentValue);
    }
  );

  return minMaxArray;
}


Solution 1:[1]

The trick consist in provide an empty Array as initialValue Parameter

arr.reduce(callback, [initialValue])

initialValue [Optional] Value to use as the first argument to the first call of the callback. If no initial value is supplied, the first element in the array will be used.

So the code would look like this:

function minMax(items) {
    return items.reduce((acc, val) => {
        acc[0] = ( acc[0] === undefined || val < acc[0] ) ? val : acc[0]
        acc[1] = ( acc[1] === undefined || val > acc[1] ) ? val : acc[1]
        return acc;
    }, []);
}

Solution 2:[2]

In ES6 you can use spread operator. One string solution:

 Math.min(...items)

Solution 3:[3]

You can use array as return value:

function minMax(items) {
    return items.reduce(
        (accumulator, currentValue) => {
            return [
                Math.min(currentValue, accumulator[0]), 
                Math.max(currentValue, accumulator[1])
            ];
        }, [Number.MAX_VALUE, Number.MIN_VALUE]
    );
}

Solution 4:[4]

You can use do like this. There can be any number of arguments.

function minValue(...args) {
    const min = args.reduce((acc, val) => {
        return acc < val ? acc : val;
    });
    return min;
}

function maxValue(...args) {
    const max= args.reduce((acc, val) => {
        return acc > val ? acc : val;
    });
    return max;
}

Solution 5:[5]

The solution using Math.min() and Math.max() functions:

function minMax(items) {
    var minMaxArray = items.reduce(function (r, n) {
            r[0] = (!r[0])? n : Math.min(r[0], n);
            r[1] = (!r[1])? n : Math.max(r[1], n);
            return r;
        }, []);

    return minMaxArray;
}

console.log(minMax([4, 1, 2, 7, 6]));

Solution 6:[6]

As the reduce call isn't really needed at all, you could have some fun with it

let items = [62, 3, 7, 9, 33, 6, 322, 67, 853];

let arr = items.reduce((w,o,r,k,s=Math)=>[s.min.apply(0, k),s.max.apply(0, k)],[]);

console.log(arr);

All you'd really need is let minMaxArray = [Math.min.apply(0,items), Math.max.apply(0,items)]

Solution 7:[7]

const values = [1,2,3,4,5];
const [first] = values;
const maxValue = values.reduce((acc, value) => Math.max(acc, value), first);

Solution 8:[8]

To get min and max value of an array using reduce function

const ArrayList = [1, 2, 3, 4, 3, 20, 0];
const LargestNum = ArrayList.reduce((prev, curr) => {
      return Math.max(prev, curr)
});
const MinNum = ArrayList.reduce((prev,curr)=>{
      return Math.min(prev,curr)
});
console.log(LargestNum);
console.log(MinNum);

Solution 9:[9]

1. Solution using only Math.min and Math.max:

?? This will not work if you use big arrays, i.e. supply Math.min() with many arguments as "you run the risk of exceeding the JavaScript engine's argument length limit. The consequences of applying a function with too many arguments (think more than tens of thousands of arguments) vary across engines (JavaScriptCore has hard-coded argument limit of 65536), because the limit (indeed even the nature of any excessively-large-stack behavior) is unspecified. Some engines will throw an exception." from MDN web docs.

function minMax(items) {
  return [
      Math.min.apply(null, items),
      Math.max.apply(null, items)
  ]
}

... or if you prefer ES6's Spread syntax:

const minMax = items => [
  Math.min(...items),
  Math.max(...items)
]

2. Solution using Array.prototype.reduce, Math.min and Math.max

function minMax(arr) {
  return arr.reduce(function(acc, cur) {
    return [
      Math.min(cur, acc[0]),
      Math.max(cur, acc[1])
    ]
  }, [Number.POSITIVE_INFINITY, Number.NEGATIVE_INFINITY]);
}

... or shortened:

const minMax = items =>
  items.reduce((acc, cur) =>
    [Math.min(cur, acc[0]), Math.max(cur, acc[1])],
    [Number.POSITIVE_INFINITY, Number.NEGATIVE_INFINITY]
  )

3. Solution including sensible validations

function minMax(items) {
  let newItems = []
  const isArray = Array.isArray(items)
  const onlyHasNumbers = !items.some(i => isNaN(parseFloat(i)))

  // only proceed if items is a non-empty array of numbers
  if (isArray && items.length > 0 && onlyHasNumbers) {
    newItems = items.reduce((acc, cur) => [
        Math.min(cur, acc[0]),
        Math.max(cur, acc[1])
      ], [Number.POSITIVE_INFINITY, Number.NEGATIVE_INFINITY])
  }

  return newItems
}

Documentation for Math.min

Documentation for Math.max

Documentation for Array.prototype.reduce()

Solution 10:[10]

Here is an example of reduce vs Array

const result = Array(-10,1,2,3,4,5,6,7,8,9).reduce((a,b)=>{ return (a<b) ? a : b })

You may want to use the same against getting length of strings

 const result = Array("ere","reeae","j","Mukono Municipality","Sexy in the City and also").reduce((a,b)=>{ return (a.length<b.length) ? a : b })

Solution 11:[11]

let arr = [8978, 'lol', -78, 989, NaN, null, undefined, 6, 9, 55, 989];


let minMax = arr.reduce(([min, max], v) => [
                Math.min(min, v) || min,
                Math.max(max, v) || max], [Infinity, -Infinity]);


console.log(minMax);

How it works:

  1. || min check is v number.

  2. [Infinity, -Infinity] is .reduce initial value

  3. It use js destructuring assignment

Solution 12:[12]

We can accomplish this by declaring an empty array as the accumulator value for the reduce function, then carrying out a different set of operations on the last iteration of the reduce method. We do this by passing all four parameters to the reduce method (total, item, index, array) and using a comparison of the index to the array length to do something different on that last iteration.

var prices = [32.99, 21.99, 6.99, 4.99, 12.99, 8.98, 5.99];

var highLowPrices = prices.reduce(function(accumulatorArray, price, index, pricesArray){
    if (index === pricesArray.length-1){
        accumulatorArray.push(price);
        var returnArray = [];
        accumulatorArray.sort(function(price1, price2){
            return price1 - price2;
        });
        var lowestPrice = accumulatorArray[0];
        var highestPrice = accumulatorArray[accumulatorArray.length-1];
        returnArray.push(lowestPrice);
        returnArray.push(highestPrice);
        return returnArray;
    } else {
        accumulatorArray.push(price);
        return accumulatorArray;
    }
}, []);

console.log(highLowPrices);

I've intentionally used a few more steps than necessary and used semantically verbose variable names to make the logic clearer.

if (index === pricesArray.length-1) means that on the last iteration of the reduce method through the prices array, a different set of operations occurs. Up to that point, we are merely recreating the prices array, which is trivial. But on the last iteration, after fully recreating the prices array, we do something different. We create another empty array, the one we intend to return. We then sort through the 'accumulatorArray' variable - which is the prices array, recreated, sorting it from lowest to highest. We now take the lowest price and highest price and store them in variables. Having sorted the array in ascending order, we know that the lowest is at index 0 and the highest, at index array.length - 1. We then push those variables into our previously declared return array. And instead of returning the accumulator variable itself, we return our own specially declared return array. The result is an array with the lowest price and then the highest price.

Solution 13:[13]

I know this has been answered but I went off of @Sergey Zhukov's answer (which seems incomplete) and was able to get the min and max values in 2 lines:

let vals = [ numeric values ]
let min = Math.min.apply(undefined, vals) 
let max = Math.max.apply(undefined, vals)

I do see the value in Array.reduce, but with such a super simple use case, and so long as you understand what Function.apply does, this would be my goto solution.