JavaScript/TypeScript doesn’t offer a function to generate a range array. What we want to do is something like this.

```
Array.range(5, 10); // [5, 6, 7, 8, 9, 10]
Array.range(2, 10, 2); // [2, 4, 6, 8, 10]
```

How can we write code for this?

I created a module called yutolity that provides the functions. Go to npm and add it to your dependencies if you don’t want to write code.

## Integer value Array Range

### Ascending order array

If we want to generate an integer array like `[1, 2, 3, 4]`

we can generate it with this one line.

```
const res = Array.from(Array(5).keys()).map(x => x + 1);
console.log(res);
// [1, 2, 3, 4, 5]
```

If we want to start the array from 5 we need to change `x + 1`

to `x + 5`

;

```
const res = Array.from(Array(5).keys()).map(x => x + 5);
console.log(res);
// [1, 2, 3, 4, 5]
```

Let’s make it to a function.

```
const range = (start, end) => Array.from(Array(end - start + 1).keys()).map(x => x + start);
console.log(range(3, 6));
// [3, 4, 5, 6]
console.log(range(-2, 2));
// [-2, -1, 0, 1]
```

### Descending order array

The code shown above doesn’t work if the end value is smaller than the start. Let’s improve it.

```
export function range(start: number, end: number): number[] {
start = Math.floor(start);
end = Math.floor(end);
const diff = end - start;
if (diff === 0) {
return [start];
}
const keys = Array(Math.abs(diff) + 1).keys();
return Array.from(keys).map(x => {
const increment = end > start ? x : -x;
return start + increment;
});
}
```

The last 5 lines are the main logic. It looks more complected but it’s not hard. It just decides if it increments or decrements.

## Floating value Array Range

If we want to generate a floating value array we need to implement it in a different way. Following is the first code that I wrote.

```
export function rangeByStep(start: number, end: number, step: number): number[] {
if (end === start || step === 0) {
return [start];
}
if (step < 0) {
step = -step;
}
const stepNumOfDecimal = step.toString().split(".")[1]?.length || 0;
const endNumOfDecimal = end.toString().split(".")[1]?.length || 0;
const maxNumOfDecimal = Math.max(stepNumOfDecimal, endNumOfDecimal);
const power = Math.pow(10, maxNumOfDecimal);
const increment = end - start > 0 ? step : -step;
const intEnd = Math.floor(end * power);
const isFulFilled = end - start > 0 ?
(current: number) => current > intEnd:
(current: number) => current < intEnd
const result = [];
let current = start;
while (true) {
result.push(current);
// to address floating value
const intValue = Math.floor(current * power) + Math.floor(increment * power);
current = intValue / power;
if (isFulFilled(intValue)) {
break;
}
}
return result;
}
```

It’s much more complected than the one for the integer version because it’s not so simple to handle floating value. When repeating to add 0.1 to the existing variable its result is 0.200000001 for example. Therefore, I converted the floating values to integers and then started calculation to prevent this. Furthermore, Math.floor returns -31 if the argument is like -30.0000001. I needed to replace the function with Math.trunc.

I thought that I could remove the value comparison if I wrote in the same way as the integer version. The second version is the following.

```
export function rangeByStep(start: number, end: number, step: number): number[] {
if (end === start || step === 0) {
return [start];
}
if (step < 0) {
step = -step;
}
const stepNumOfDecimal = step.toString().split(".")[1]?.length || 0;
const endNumOfDecimal = end.toString().split(".")[1]?.length || 0;
const maxNumOfDecimal = Math.max(stepNumOfDecimal, endNumOfDecimal);
const power = Math.pow(10, maxNumOfDecimal);
const diff = Math.abs(end - start);
const count = Math.trunc(diff / step + 1);
step = end - start > 0 ? step : -step;
const intStart = Math.trunc(start * power);
return Array.from(Array(count).keys())
.map(x => {
const increment = Math.trunc(x * step * power);
const value = intStart + increment;
return Math.trunc(value) / power;
});
}
```

The following code gets the length of the number after the decimal point.

```
const stepNumOfDecimal = step.toString().split(".")[1]?.length || 0;
const endNumOfDecimal = end.toString().split(".")[1]?.length || 0;
// 11 -> 0
// 11.123 -> 3
// 123.12345 -> 5
```

This function can do the same thing that I wrote at the top of this article.

```
Array.range(2, 10, 2); // [2, 4, 6, 8, 10]
rangeByStep(2, 10, 2); // [2, 4, 6, 8, 10]
```

## Handle Big/Small Number with Log Notation

However, it can’t cover some cases when the number is very big or small because those numbers can be converted to log notation.

```
console.log(0.000000001);
// 1e-9
```

My function checks the length after the decimal point but it doesn’t work without dot “.”. The logic needs to be updated. The improved code is following.

```
export function indexesOf(
text: string,
searchStrings: string[],
position?: number
): IndexOfResult | undefined {
for (const searchString of searchStrings) {
const index = text.indexOf(searchString, position);
if (index !== -1) {
return {
index,
foundString: searchString,
};
}
}
}
export function getPrecision(value: number): number {
const str = value.toString();
const searchStrings = ["e-", "e+"];
const found = indexesOf(str, searchStrings);
if (found) {
return parseInt(str.substring(found.index + 2));
}
return str.split(".")[1]?.length || 0;
}
getPrecision(11.223); // 3
getPrecision(11.0); // 0
getPrecision(1e-11); // 11
getPrecision(1e+21); // 21
```

Even if it receives a log notation value it can get the precision. If we replace it with the previous version `rangeByStep`

function supports all most all cases. I’m sure this is probably too much. In most cases, such a big/small number isn’t used.

## End

The logic to generate an integer range array is easy but not for a floating value. We need to consider calculation error and log notation. It was a cumbersome calculation. I guess we use a normal integer range array in most cases so you can easily write the code yourself. Copy my code and paste it.

If you want to use the utility functions shown in this article you can add my module yutolity.

## Comments