# Array.range() for generating sequences

**URL:** <https://es.discourse.group/t/array-range-for-generating-sequences/146>\
**Category:** 💡 Ideas\
**Created:** [December 6, 2019, 7:17pm UTC](https://es.discourse.group/t/array-range-for-generating-sequences/146 "2019-12-06T19:17:28Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![DavidSampson](https://avatars.discourse-cdn.com/v4/letter/d/b5e925/32.png) [@DavidSampson](https://es.discourse.group/u/DavidSampson)\
**Post date:** [December 6, 2019, 7:17pm UTC](https://es.discourse.group/t/array-range-for-generating-sequences/146/1 "2019-12-06T19:17:28Z")

</div>

It is reasonably common to need an array populated by a simple sequence of numbers, usually to manipulate them later. Uses include:

- Generating page numbers (`<a href="page1.html">1</a>`)
- Retries (n attempts to login before being locked out)
- Mathematics (any ranged sum or product, combinatorics, Taylor/Maclaurin series, partial harmonic series, Fourier series...)

Currently these can be created imperatively via `for` loop:

```javascript
function range(start, stop, step){
  let arr = [];
  for(let i = 0; i < start+stop; i++){
    arr[i] = start + (i * step);
  }
  return arr;
}

```

(Of course, one could elect to make any manipulations they wanted inside the `for` loop, rather than generating the array and then manipulating it.)

One can also create such an array more functionally using array methods in various ways:

```javascript
const range = (start, stop, step) => Array((stop - start) / step)
                                      .fill(0)
                                      .map((_,i) => start + (i * step));
// or
const range = (start, stop, step) => Array(stop - start)
                                      .fill(0)
                                      .map((_,i) => start + i)
                                      .filter(v => (v-start) % step === 0)

```

The `for` loop solution has detractors simply due to its use of `for` loops, but in any case it uses a fair amount of code for a fairly simple concept.

The same problem applies to the `Array` method approach -- an array created via `Array(n)` cannot be meaningfully mapped over until it is filled with something either via `for` loop or with `Array.prototype.fill()`, which can only fill with a constant value. Meaning a third step (at least) is required to generate the final array, and at least two passes over the entire array.

Additionally, the `Array` methods approach has a lot of potential pitfalls (there are issues with both of my demo implementations, edge cases where they don't work, etc).

I think it would be useful to have a static method on `Array`, tentatively called `Array.range`, with the following semantics:

- `Array.range(stop: number)` -- for any positive `stop` return an array of integers in the interval `[0, Math.ceil(stop) - 1]` inclusive, ordered from least to greatest. For any negative `stop` return an array of integers in the interval `[Math.floor(stop) + 1, 0]` inclusive, tentatively ordered from greatest to least (though I'd be open to arguments either way on that). For `stop === 0`, return `[]`, or possibly `[0]`, it's up for discussion.
- `Array.range(start: number, stop: number, step = 1)` -- If `start` is less than `stop`, return an array of the set of all `n_k = start + k*Math.abs(step)` where `k` is a non-negative integer and `n_k` is in the interval `[start, stop)` (note that it is inclusive on the low end, exclusive on the high end a la `Array.prototype.slice()`). If `start` is greater than `stop`, returns an array of the set of all `n_k = start - k * Math.abs(step)` where `k` is a non-negative integer and `n_k` is in the interval `[start, stop)` with the same restrictions as the prior case. Throw an error (`RangeError`?) on `step === 0`. Either throw an error, or return `[]` or `[start]` on `start === stop`.
- Possibly? `Array.range(start: number, stop: number, step: number, modifier: (value: number index: number)=> number)` with the same logic as the prior case, but the function `modifier` is mapped across the resultant array in the same pass as creation (reducing the need to then immediately call `.map()` on the array, which would also introduce an additional pass over the array)

I think that having this baked into the `Array` class would allow for some optimizations at the interpreter level that would be more difficult or impossible to do in a library, such as making the creation slightly more lazy in some cases.

Is this (or a version of this) something that anyone else would support?

---

<div class="post-metadata">

**Author:** ![jridgewell](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/jridgewell/32/18_2.png) [@jridgewell](https://es.discourse.group/u/jridgewell)\
**Post date:** [December 6, 2019, 8:06pm UTC](https://es.discourse.group/t/array-range-for-generating-sequences/146/2 "2019-12-06T20:06:13Z")

</div>

Hi David,

This seems like a natural extension for [https://github.com/tc39/proposal-slice-notation](https://github.com/tc39/proposal-slice-notation)?

---

<div class="post-metadata">

**Author:** ![ljharb](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/ljharb/32/8_2.png) [@ljharb](https://es.discourse.group/u/ljharb)\
**Post date:** [December 6, 2019, 10:33pm UTC](https://es.discourse.group/t/array-range-for-generating-sequences/146/3 "2019-12-06T22:33:43Z")

</div>

There's also a much older proposal, [http://array.build](http://array.build), which could be relevant.

---

<div class="post-metadata">

**Author:** ![jridgewell](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/jridgewell/32/18_2.png) [@jridgewell](https://es.discourse.group/u/jridgewell)\
**Post date:** [December 6, 2019, 11:03pm UTC](https://es.discourse.group/t/array-range-for-generating-sequences/146/4 "2019-12-06T23:03:34Z")

</div>

Yes! Please! `Array.build` seems wonderful.

---

<div class="post-metadata">

**Author:** ![metanomial](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/metanomial/32/173_2.png) [@metanomial](https://es.discourse.group/u/metanomial)\
**Post date:** [December 12, 2019, 4:01pm UTC](https://es.discourse.group/t/array-range-for-generating-sequences/146/5 "2019-12-12T16:01:21Z")

</div>

```javascript
const arr1 = [1:6]; // [1, 2, 3, 4, 5, 6]
const arr2 = [1:7:2]; // [1, 3, 5, 7]
const arr3 = [1:4, 10:20:5, 4, 2:4]; // [1, 2, 3, 4, 10, 15, 20, 4, 2, 3, 4]

for(const n of [4:8]) { ... }

[10:100:10][0:4]; // [10, 20, 30, 40]

```

---

<div class="post-metadata">

**Author:** ![JackWorks](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/jackworks/32/260_2.png) [@JackWorks](https://es.discourse.group/u/JackWorks)\
**Post date:** [March 8, 2020, 1:17pm UTC](https://es.discourse.group/t/array-range-for-generating-sequences/146/6 "2020-03-08T13:17:49Z")

</div>

There is another proposal for it [https://github.com/Jack-Works/proposal-Number.range](https://github.com/Jack-Works/proposal-Number.range)
