**Challenge:**

1 2 |
We'll pass you an array of two numbers. Return the sum of those two numbers and all numbers between them. The lowest number will not always come first. |

**Solution should return:**

1 2 3 4 5 |
sumAll([1, 4]) should return a number. sumAll([1, 4]) should return 10. sumAll([4, 1]) should return 10. sumAll([5, 10]) should return 45. sumAll([10, 5]) should return 45. |

**Helpful links I was provided with:**

This was a bit tricky, and I had to make use of the Babel repl to transform my hybrid Javascript consisting of ES5 and a bit of ES6 into consistent Javascript code. Babel really came in handy! To learn more about Babel, please read my post entitled “Babel: a great way to learn ES6”.

First I had to make sense of what my solution was supposed to return. It was immediately obvious to me that the arguments provided within the [] did not consist of a complete array. What then, did those arguments represent? I analyzed the relationship between the arguments and the number following. It occurred to me that probably 10, 10, 45, and 45, were sums of arrays. That probably meant that the array arguments within [] were min and max (or max and min) of the array(s).

At first I thought that I could simply do the following:

1 2 3 |
function sumOf(min, max) { return (max - min + 1) * (min + max) / 2; } |

The formula (max-min +1) * (min + max) / 2 is based on the Gaussian formula sum from 1 to n:

Please visit Techniques for Adding the Numbers 1 to 100 to learn more. However, I first learned about it on StackExchange in which the (max-min +1) * (min + max) / 2 was being used, an adaptation to the sum of an array in which only the min/max || max/min of the array was provided. If you read Techniques for Adding the Numbers 1 to 100, you’ll see why it makes sense.

But my sumOf(min,max) would only work if sumAll([]) consisted of sumAll([min,max]) arguments only. What if it was sumAll([max,min])? Then it would not work. I had to take the possibility of the opposite scenario into account.

How to do that then?

Recently I have been learning a bit about ES6, and one of the topics was the spread operator. The spread operator is amazing, but it is part of ES6 and not ES5.

**spread operator:** allows an expression to be expanded in places where multiple arguments (for function calls) or **multiple elements (for array literals)** or multiple variables (for destructuring assignment) are expected. In other words, you don’t have to write out, in this case, the whole array. …arr2 is the same as [3,4,5].

**An example:**

1 2 |
var parts = ['shoulders', 'knees']; var lyrics = ['head', ...parts, 'and', 'toes']; // ["head", "shoulders", "knees", "and", "toes"] |

With ES5, if you have an array and want to create a new array with the existing one being part of it, the array literal syntax is no longer sufficient and you have to fall back to imperative code, using a combination of `push`

, `splice`

, `concat`

, etc. With spread syntax this becomes much more succinct.

My “problem” was that I was only provided the **min and max/max and min of arrays** as arguments and had to “reconstruct” the arrays from which they originated. I only knew how to do this utilizing the spread operator, so my next solution included the spread operator.

**Solution including spread operator:**

1 2 3 4 5 6 7 8 |
function sumOf(min, max) { return (max - min + 1) * (max + min) / 2; } function sumAll(arr) { return sumOf(Math.min(...arr), Math.max(...arr)); } sumAll([1, 4]); |

I don’t consider this “best practice”. Either I should consistently use ES6 or consistently use ES5. That’s where Babel came in! I placed this code on the left side of the repl, and got the following code transpilation on the right:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
"use strict"; function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } } function sumOf(min, max) { return (max - min + 1) * (max + min) / 2; } function sumAll(arr) { return sumOf(Math.min.apply(Math, _toConsumableArray(arr)), Math.max.apply(Math, _toConsumableArray(arr))); } sumAll([1, 4]); |

This was all well and good, but there was some code native to Babel that was not “pure” Javascript. I had to decipher what was what, and then take the code transpilation even further. I came up with the following in my first “Consumable Solution”:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
function consumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } } function sumOf(min, max) { return (max - min + 1) * (max + min) / 2; } function sumAll(arr) { return sumOf(Math.min.apply(Math, consumableArray(arr)), Math.max.apply(Math, consumableArray(arr))); } sumAll([1, 4]); |

I looked up _toConsumableArray(arr) {}. The underscore in front of toConsumableArray() reminded me a lot of lodash syntax, and I figured that it must be something specific to Babel. When I conducted a Google Search, this is what I found:

https://github.com/emberjs/ember.js/issues/10730:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
'use strict'; var _toConsumableArray = function(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) arr2[i] = arr[i]; return arr2; } else { return Array.from(arr); } }; function doIt(foo) { blah.apply(undefined, _toConsumableArray(foo)); } |

I had to make sure that my code consisted only of “pure” Javascript, and no Babel. So that’s why consumableArray(arr) instead. The other thing I discovered, was that there was a known issue in Babel regarding the transpilation of the ES6 spread operator. I experienced it as well, and it appears in one of my code snippets here. Take a look at the left-side Babel repl code beneath “**Solution including spread operator” **where I use the spread operator in the sumAll(arr) function. This is a great way of dealing with an array that has been reduced to its min/max || max/min elements because the spread operator “expects” there to be other elements in between. And here, that is the case! That part is fine, as it resides on the left of the Babel repl. It’s what appears on the right that is of concern to many. Purportedly, Babel should be transpiling ES6 to ES5. However, in the case of the spread operator, it is generating some ES6 to work around other ES6. It should not be doing that. Some users have been complaining that this issue has resulted in the failing of their builds that include this code. In my transpilation, Babel produced

1 2 3 4 5 6 7 8 9 10 |
function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } } |

Please visit Spread operator with NodeList converts to ES6 feature Array.from() to learn more. ES6’s Array.from(); on MDN

This meant that I had to transform my code even more to come up with more consistent, prettier, and purer ES5. But first I had to make sure that I understood every facet of the Babel transpilation I had received.

In my “First Consumable Solution” code, Array.from() was present. My consumableArray() hack was also present. Did I really need the latter, I wondered. Then there was the presence of the Math argument:

1 2 3 |
function sumAll(arr) { return sumOf(Math.min.apply(Math, consumableArray(arr)), Math.max.apply(Math, consumableArray(arr))); } |

This came up in the first Babel transpilation. I had never seen Math.min() or Math.max() used in this way, and wanted to understand what it meant and what it did. I removed the Math argument to see what would happen. This made sumAll([1, 4]); return NaN. This happens when at least one of the arguments can’t be converted to a number. All I had was *arr, *and that evidently was not being converted to a number(s). Well, that wasn’t good. This made Math an indispensable component of the solution. So the question was, what to do next to make my code purer and more succinct?

I had to find out why Math was so important to the solution, and its best practice implementation. Perhaps the body of sumAll() was where the code was getting too verbose. I looked up Math.min.apply(Math, arr); I thought since sumAll() had arr as a param, and the reduced array that was called to sumAll() as an argument was the value of the arr parameter, that I should be able to remove consumableArray from consumableArray(arr) and be left with arr as the second argument in Math.min.apply()/Math.max(apply). I did a Google Search to find out whether my assumption was correct. This is what I came up with:

It might be from 2007, but it still applies, and is a most informative read.

This was the **final solution** I came up with:

1 2 3 4 5 6 7 8 |
function sumOf(min, max) { return (max - min + 1) * (max + min) / 2; } function sumAll(arr) { return sumOf(Math.min.apply(Math, arr), Math.max.apply(Math, arr)); } sumAll([1, 4]); |

Much more succinct, and most definitely *much* more pure than the first iteration, right? Despite the Babel “issue”, Babel still proved invaluable in my ES6 (and Javascript in general) education!

**Note:** You could also use null instead of Math, but then the potential argument length is greater than if you use the Math argument which refers to either the min or max of the array. The use of null also results in more verbose code. To learn more, please visit Function.prototype.apply() on MDN.

**Solution in ES6:**

1 2 3 4 5 6 7 8 |
function sumOf(min, max) { return (max - min + 1) * (max + min) / 2; } function sumAll(arr) { return sumOf(Math.min.apply(Math, arr), Math.max.apply(Math, arr)); } sumAll([1, 4]); |

This was first published here on **May 30, 2016 @ 21:06**. It is part of freecodecamp.org’s **Intermediate JavaScript Algorithm Scripting** for the **Front End Development** certification.

Comment Policy:Your words are your own, so be nice and helpful if you can. Please, only use your real name and limit the amount of links submitted in your comment. We accept clean XHTML in comments, but don't overdo it please. Comments are moderated, so spammy or malicious links will be removed.