`range`

is a function that basically takes in a starting index and ending index then return a list of all integers from start to end.

The most obvious way would be using a for loop.

```
function range(start, end) {
var ans = [];
for (let i = start; i <= end; i++) {
ans.push(i);
}
return ans;
}
```

As a fan of FP, let's come up with an recursive solution. So the base case is obviously when the start and end are the same, the answer would simply be `[start]`

.

```
function range(start, end) {
if(start === end) return [start];
// recursive case
}
```

Now take the leap of faith, assume that `range(start, end)`

will *just work*. Then how do we solve the problem `range(start, end)`

? Simple! Just do `[start, ...range(start + 1, end)]`

.

So combining both, we get

```
function range(start, end) {
if(start === end) return [start];
return [start, ...range(start + 1, end)];
}
```

A lot more elegant than the for-loop solution in my opinion. But we could even go further if we use `new Array(n)`

which creates an array with n elements.

If we have an n element list, we could build a range from it by mapping each element to its index, i.e. `arr.map((_, i) => i)`

.

However, according to https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map#Description, `map`

will not call for unassigned element. This mean we need to initialise the `new Array(n)`

before mapping. One standard technique is to use `fill`

. The final result is the following.

```
function range(start, end) {
return (new Array(end - start + 1)).fill(undefined).map((_, i) => i + start);
}
```

Thank you Step for mentioning about efficiency when handling large ranges, which essentially build a large array. We could have a more efficient way of doing this by using generators.

```
function* range(start, end) {
for (let i = start; i <= end; i++) {
yield i;
}
}
```

We could use this generator in a `for...of`

loop (which would be very efficient) or use an array spread to retrieve all values (note that this essentially builds the array which is essentially the same as the non-generator approaches.)

```
for (i of range(1, 5)) {
console.log(i);
}
/* Output
* 1 2 3 4 5 */
[...range(1, 5)] // [1, 2, 3, 4, 5]
```

Since I always try to avoid for loops, we could also define the generator recursively as follows.

```
function* range(start, end) {
yield start;
if (start === end) return;
yield* range(start + 1, end);
}
```

Could you think of some cooler method to achieve this?