Another Look at Finding Minimum and Maximum in Arrays

I recently saw an exercise for finding a minimum and maximum value in an array. The wording of the question, which I won’t repeat here, hinted you to do that with a bit story behind it. Then, I reminisced about the good old days and attacking the problem with a simple for loop. You know, the one with a variable defined above the for loop and you keep checking the next value in the for loop against this variable so you could update it if necessary. Luckily, we now have array methods such as forEach, map, filter etc.

Filter and map can’t help us here since we are only interested in one final value than shrinking the said array or converting the array values. ForEach is no different than using plain old for loop really.  How about reduce?

Why Not Sort?

Alternatively, you could sort the array and reach for the first and last index to gather minimum and maximum values. However, you’d have to write a custom sort function to do that since the default sorting will be done alphanumerically as per MDN.

The default sort order is built upon converting the elements into strings, then comparing their sequences of UTF-16 code units values.

Therefore, sorting isn’t any better than using reduce at this point. So, let’s use reduce to find the minimum of this array, [10, 7, 5, 8, 11, 9].

stock_prices.reduce((a, b) => Math.min(a, b));

Nothing particularly interesting here. Just as most reduce examples do it, we play with the value of accumulator and the current value. The accumulator stores the result of Math.min so its value is compared against the next item in the array. After all the pairs is compared, the result is the minimum of all pairs. Similarly, the following code finds the maximum.

stock_prices.reduce((a, b) => Math.max(a, b));

Can We Do Better?

As far as the ask goes, we are done here but can we do better than going over the same array twice? In other words, could we find the minimum and the maximum in one go? Sure, we can. it’s time to take advantage of that initialValue argument of reduce again. I’ve written an example of using it for removing duplicates from an array if you are interested in a different use case. Let’s break down the following piece of code.

let minmax = stock_prices.reduce(
  (prices, currentPrice) => {
    return Object.assign(prices, {
      min: Math.min(prices.min, currentPrice),
      max: Math.max(prices.max, currentPrice)
    });
  },
  { min: 0, max: 0 }
);

Since Javascript has no tuples, we need an object to store the two values we want to capture. Therefore, the initialValue argument will be an object with min and max keys. I used 0 as start values since I knew the input array would not have negative values. Feel free to start off with negative and positive infinity respectively if your array has a wide range of values. The accumulator argument in reduce, prices, will now refer to initialValue object so in each turn the accumulator will have an object signature just like initialValue we are passing. This is why I used Object.assign to merge the incoming prices object with the new object we are creating with more current min and max keys. This is, in essence, combining the previous two separate reduce calls into one. The detail here is that prices object is no longer a straight value you can compare against currentPrice due to initialValue. So, instead, do your comparison against its min and max values.

In the end, minmax is an object with two keys, min and max with the same exact values you found as shown earlier in this article.


Recent posts