Sum All Numbers in a Range. Best way to solve it

Hi all. I’ve solved the problem with the sum of the numbers in a range but I want to find out if this is the best way to solve it. I have solved with arr.sort() and I have used [0] and [1] to get the start an finish in a for loop.

function sumAll(arr) {
  let sum = 0;

  arr.sort((x, y) => {
    return x - y;
  });

  for (let index = arr[1]; index >= arr[0]; index--) {
    sum += index;
  };

  return sum
}

sumAll([4, 1]);

Link challenge, post your code. This doesn’t explain much.

1 Like

updated, sorry for that :slight_smile:

yup, that works quite well. Now, a suggestion – the ES6 way of thinking is less about the “how” of things, and more about the “what”. The for loop works, and works quite well, but you’re having to tell javascript explicitly how it is to iterate over the array, as well as telling it what you want done to each member.

But, with ES6, that changes. We no longer have to write the mechanisms to iterate over arrays, for example. We have higher-order functions like .map(), .filter() and .reduce(). These will iterate over an array, without us having to specify the means that javascript will use to do so.

In the version of this I had written, I used three Array methods (in addition to the .sort(), which I defined exactly as you did). I wanted to return an array, fill()ed with empty members, which I then map()ped to the range of values, and then reduce()d to a single, sum, value.

Not saying AT ALL that your solution is wrong. It truly isn’t. But as you move on in your coding journey, you’ll find that there is always a different way to solve a problem.

What is meant by the best way, though? Is it the most elegant? The most time-efficient? It really depends on the needs. Here’s what I did:

  • I wrote the same functionality as two functions, sumAll() and sumAll2(). The first is using map/reduce, and the second is the straightforward for loop.
  • I wrapped the call to each one in a handy timing gadget, console.time() and console.timeEnd() – not 100% perfect as a benchmark, but great for comparing.
function sumAll(arr) {

  // First, order them least to greatest.
  arr.sort((x, y) => {
    return x - y;
  });
 
  /***
   * The following chained series of functions does quite a lot:
   *  - create an empty Array of the length of our range,
   *  - fill() the array with undefined for each member,
   *  - map() the values from start to finish into each member,
   *  - reduce() the array to the single, sum, value.
   ***/ 
  return Array(arr[1] - arr[0] + 1)
        .fill()
        .map((item, index) => arr[0] + index)
        .reduce((sum, current)=>sum+current, 0);

}

function sumAll2(arr){
    let sum = 0;

  arr.sort((x, y) => {
    return x - y;
  });

  for (let index = arr[1]; index >= arr[0]; index--) {
    sum += index;
  };

  return sum;
}

// Wrapping the function call in time() and timeEnd() displays the
//  elapsed time our function took.
console.time("sumAll");
console.info("Using map() and reduce: "+sumAll([20000, 1]) );
console.timeEnd("sumAll");

console.time("sumAll2");
console.info("Using a for loop: "+sumAll2([20000, 1]) );
console.timeEnd("sumAll2");

Interestingly, in this case, your way is MUCH faster. I used a pretty high number for our range, simply to drive home the difference, but it scales in both cases – yours is about seven times faster, every time.

Using map() and reduce: 200010000
sumAll: 7.228ms
Using a for loop: 200010000
sumAll2: 1.066ms

You can test this out with different values for sumAll() and sumAll2() on my repl.

It might make it a bit slower but a good habit to get into is creating a new array rather than mutating the argument the function is given.

ex.

const arr2 = [...arr].sort((a, b) => a - b);

This will make it so the function is “pure” which basically means it has no side effects

1 Like

So first up, read the instructions carefully here.

Firstly: you are always given an array of two numbers, so you don’t need to use sort.

Say you have two numbers, a and b, and you want to know which is the smallest. If b - a < 0, then it’s b, otherwise it’s a.

function sumAll([a, b]) {
  if (b - a < 0) [a, b] = [b, a];

(I’ve used destructuring to swap the variables, but it doesn’t need to use that, or any es6 feature)

Secondly, if you know where the sequence starts (this is a in the spoilered example above) and the length of the sequence (let’s call it rangeLen, and it is b - a in the spoilered example, largest - smallest), just calculate the sum (just Google “sum of sequence” or “Gauss sum sequence” for the equation used for this eg). You don’t need a loop or anything fancy:

const start = a;
const rangeLen = b - a + 1;

return (rangeLen * ((2 * start) + (rangeLen - 1))) / 2;

So doing this is much more efficient than anything involving loops, or sorts, etc. Computers are really fast when it comes to basic arithmetic. If you are faced with a challenge that involves maths-based stuff, check it doesn’t have a simple answer where you can just take the values and plug them into an equation.

2 Likes

Ah, but be mindful, @kevinSmith weighed in on a similar conversation about that very thing. It is an algebraic trick to get the same result. Yes, it works, and yes, it is a GREAT time-saver, but the purpose of the lesson (according to his reply here) is to work on algorithms to solve the problem, rather than a reliance on a knowledge of algebra that may or may not be present.

That said, it is a phenomenal solution, and it reduces the time dramatically. This is, to my mind, the best possible time-wise solution. And if you can whip this out during an interview question, you’ll either impress them with your mad skillz, or you’ll piss them off with your “smart-aleck-itude”. And I added that to the repl, just to compare times. This solution stays consistently around 0.3 ms, blowing the doors off the others. :wink:

I get you. I would disagree on it being mad skillz or smart-aleckey for a few reasons though, not least that this is an algorithmic solution — basic adding/subtracting/multiplying/dividing are just as valid as using loops or built in array methods.

  1. It’s a sum, involving a known, non-random sequence of numbers (integers!). There is likely to be some trivial equation that provides a solution.
  2. I haven’t done maths since school, so it’s not likely I know this in advance (I happen to know it is trivial to calculate the sum of a sequence, but that is because someone told me there was a simple solution to a similar coding problem years ago). It’s not a cheat or a trick. If I thought there was a solution I would just spend a bit of time Googling or searching SO.
  3. If there is an equation that values can just be [consistently] plugged into, then it is likely that will be the best solution (full stop), for time and efficiency and any other reason you can think of.
  4. Generally, programming languages with ranges built into the language store them like {min, max}. Kinda like this! How can they efficiently run operations on ranges? I don’t know the full spread of approaches to this (just for some situations in some languages), but if I was implementing ranges, I would want to make methods that operate on them as efficient as possible.
1 Like

So I was looking at this thread and got to this section of challenges today, and just so you know, solution posted in your last repl does not actually return correct result.
Edit: it does work fast though, I will give you that. :smiley:

1 Like

Off-by-one error, edited in original (const rangeLen = b - a + 1)

Yeah, that works fine. My solution was:

function sumAll4(arr) {

if (arr[0]>arr[1]) arr=[arr[1],arr[0]];

let sum=0;

for (let i=arr[0];i<=arr[1];i++){

sum+=i;

}

//console.log(arr+" : " +sum);

return sum;

}

It works decently fast, but as expected math solution is still more then 10 times faster.

As to the short solution being “smart-alecky”, I think it depends on how you handle it. If I were given a problem like this in an interview, I’d say, “Of course, I could use Gauss’ trick to solve this formulaicly in one line. Would you like to see that first or would you rather I do this with a looping algorithm?”

As to if the Gauss trick is an algorithm or not, I think it is in the most general sense. An algorithm is a list of instructions. The Gauss trick is just one instruction: apply this short formula. Is a list of one still a list? Technically yes.

To be honest, I’m surprised more people don’t know the Gauss story. I thought it was common knowledge. But then, I have always been interested in the history of science and math.

How should you solve this? I don’t know, just do it. But I think the intent is clear - you are meant to work on you JS skills. I think they want you to solve it with a loop. And, to be honest, if solving this with a loop is anything but super easy, we need the practice.

But, whatever. No one is going to check your FCC account to confirm that you solved it the “best” way. It’s about learning. Both approaches have something to teach.

1 Like

Let us face facts, Kevin - you’re a maths and trivia nerd. One of the things we love about you, your trivial head full of knowledge. …scratch that, reverse it.

1 Like

Just a plug - one of the places that story is mentioned in the great book, Euclid’s Window. It’s a story of the history of thought on geometric space, from ancient Egypt to String Theory. He makes the concepts easy to understand and talks about the different personalities and really brings them to life.

3 Likes

In this case, the parameter is send as an array directly in function call

sumAll([4, 1]);

this information will be deleted after function execution, so you don’t need to keep it intact.

A very informative and interesting answer
:wink:
I tried both variants and the difference is immense.
For [1,4] the difference is 3 times, for [1,200,000] is 14 times faster. Thanks a lot, now I’ll be more careful about issues like this

1 Like

Agree that it doesn’t matter much in the isolated scope of this challenge, but in the wild I would argue a function like this would be more reusable and less error prone if written as a pure function.

The issue for me wasn’t which was faster. Yes, the one step formula is immensely faster. The issue for me was which teaches JS better.

1 Like