46

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;
}
Alyssa June
  • 635
  • 2
  • 6
  • 11
  • It appears you forgot to actually ask a question. Please review [ask]. – zzzzBov Apr 23 '17 at 20:40
  • 5
    `but I know that the reduce() method always returns an array of size 1` - this is incorrect. Also, reduce is just a method to iterate over an array with a callback, think about what other variables you can have in scope inside your `minMax` method that you can use in the iterator. Hint: From your description, you don't necessarily have to use the return value of `reduce` at all. – Adam Jenkins Apr 23 '17 at 20:40
  • Read the [reduce() docs](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce?v=control) and change the `initValue` of `accumulator` – charlietfl Apr 23 '17 at 20:41

16 Answers16

54

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

 Math.min(...items)
Sergey Zhukov
  • 649
  • 5
  • 7
  • 1
    Is asking for the Min and the Max. – colxi Apr 27 '18 at 01:03
  • 1
    Nice. I did't know you can use Math.min like this. I've been doing Math.min(a,b) only. – Lonelydatum Sep 13 '18 at 14:06
  • 4
    This crashes with big arrays – Jimmy Kane Sep 21 '18 at 18:48
  • 13
    To elaborate on @JimmyKane answer, if you use big arrays, i.e. supply `Math.min()` with many arguments: > "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), ..." https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/apply#Using_apply_and_built-in_functions – tobias Apr 02 '19 at 02:43
41

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;
    }, []);
}
Calsal
  • 1,375
  • 14
  • 25
colxi
  • 7,640
  • 2
  • 45
  • 43
  • 4
    This answer has the advantage of working for arbitrary ordered types (e.g. strings), rather than just numerics, which is a nice generalization. One possible optimization would be to make the `initialValue` be `[items[0], items[0]]`, so you can avoid special casing `undefined`, simplifying the min/max calculations on each call to `if (val < acc[0]) acc[0] = val;` and `if (val > acc[1]) acc[1] = val;` – ShadowRanger Jan 06 '18 at 03:30
14

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]
    );
}
  • 7
    +1, however `MIN_VALUE` is confusingly the smallest *positive* value (>0). You'd better use `Number.INFINITY` and `Number.NEGATIVE_INFINITY` – Bergi Apr 23 '17 at 21:21
  • 9
    @Bergi I think you mean `Number.POSITIVE_INFINITY`... there is no `Number.INFINITY`. – mgthomas99 Nov 21 '18 at 13:35
12

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;
}
sbgib
  • 5,580
  • 3
  • 19
  • 26
Abishek Bardewa
  • 121
  • 1
  • 3
  • This is the right solution. I failed to understand why everyone is using the `Math`'s functions when, clearly, they are not required. – attacomsian Apr 10 '21 at 05:20
  • 1
    @attacomsian I fail to understand why use `reduce`, when it's not required since it's just re-creating what `Math` already does for you. – VLAZ Jun 09 '22 at 14:25
3

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]));
RomanPerekhrest
  • 88,541
  • 4
  • 65
  • 105
3

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

adeneo
  • 312,895
  • 29
  • 395
  • 388
3

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);
Ahmed Mahmoud
  • 1,724
  • 1
  • 17
  • 21
  • In your example it works only because the latest values of the array are `20` and `0`, and are the last one compared. Just try to put the min and max values at the beginning of your array, and we will see if your code is still working :) – Alex Oct 29 '20 at 16:32
  • After putting 0,20 in the begaining of array still working no issue the output is 20,0 – Ahmed Mahmoud Oct 30 '20 at 13:51
  • Ok I read too quickly your answer, after reading again, it seems that it is correct. My apologies – Alex Nov 03 '20 at 10:12
3
const values = [1,2,3,4,5];
const [first] = values;
const maxValue = values.reduce((acc, value) => Math.max(acc, value), first);
3

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 })
Muyinda Rogers
  • 147
  • 3
  • 13
2

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

tobias
  • 934
  • 8
  • 17
0

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

SlimeSli
  • 9
  • 4
  • Welcome to Stack Overflow! Please explain your answer. Don't just write code. **For Help take a look at "[How to answer](//stackoverflow.com/help/how-to-answer)"** – tobsob Feb 05 '20 at 06:56
  • 1
    try this let arr = [8978, 'lol', 78, 989, NaN, 0, null, undefined, 6, 9, 55, 989]; – vinnitu Dec 31 '21 at 10:56
0

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.

0
let x = [4, 1, 2, 7, 6]
const r = x.reduce((acumularo, currenvalue)=>{
    if(acumularo[0]>currenvalue) acumularo[0] = currenvalue
    if(acumularo[1]<currenvalue) acumularo[1] = currenvalue
    return acumularo
},[x[0],x[0]])
console.log(r)
console.log(r[0]+r[1])
edunet
  • 1
  • 1
  • Your answer could be improved by adding more information on what the code does and how it helps the OP. – Tyler2P Nov 14 '22 at 17:27
0

Code to get max value in an Array using reduce function in Javascript

const movements = [200, 450, -400, 3000, -650, -130, 70, 1300];

const large = movements.reduce(function (acc, mov) {
if (acc > mov) {
return acc;
} else {
  return mov;
 }
}, movements[0]);

console.log(large);

Answer is : 3000

Sachindra N. Pandey
  • 1,177
  • 17
  • 15
0

function minMax(items) {
  var minMaxArray = [Math.min(...items), Math.max(...items)]
  return minMaxArray;
}
-1

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.

VLAZ
  • 26,331
  • 9
  • 49
  • 67
jusopi
  • 6,791
  • 2
  • 33
  • 44