Ranges and Generating Arrays in JavaScript

Have any of you found cool ways of generating arrays in js. I don't have to do this very often, but this is the best way I've found to do it.

const firstTenSqaures = Array.from(Array(10), (_, i) => i ** 2)

I’d suggest avoiding the Array constructor entirely - use { length: 10 } instead of Array(10).

Yeah, I know you can do that { length: 10 }, but that kind of looks like magic. Why should the Array constructor be avoided?

Because it creates a sparse array.

Right. I didn't think that would really matter here. What about?

const tenTens = new Array(10).fill(10)

I'm not sure what qualifies as cool but generators provide a lot of fun!

Array.from((function*() {
  for (let i = 0; i < 10; i++) yield i ** 2;
})()); // [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
3 Likes

There's also a range proposal: Iterator.range()

That would also be good. I feel like the question could also be phrased, what's the least ugly way to do this in js :joy:

Please refer to the active thread:

That just returns [10, 10, 10, 10, 10, 10, 10, 10, 10, 10]. If you're looking for a range, Array.prototype.fill is probably not what you're looking for.

Now if only we could get implementors to optimize it correctly.

I usually do something like:

const myRange = [...new Array(33)]
  .map((item, index) => index + 10);

But we really need a standard range functionality

1 Like

Right, I was just pointing this out as maybe an acceptable case to use the array constructor.

That's kind of esoteric knowledge that {length: n} works as an array under the hood, imo. Or is an "arrayLike" I guess.

1 Like

The problem of unintuitive code in generating arrays in JavaScript can be solved as follows:

  • Knowing the 'Number' (an unobvious pun) of array items needed.
  • Generating the array using a getter defined on the 'Number';

/* x is used as a variable below in order to bring in a sense of multiplication by some value to give
 * an array, in this case, as a result
*/
const x  = Symbol ? Symbol() : '1bda4e5b-9819-49f0-bcb3-946697b3b663';
//Symbol() does not return a string as its unique id

//x is defined on the Number.prototype object as a getter
Object.defineProperty(Number.prototype, x, {
  get() {
    /* this.valueOf below return the number that is currently accessing x as a property
     */
    let arg=[], n=this.valueOf(), i=0;
    for(; i++<n; arg[i-1]=i-1); return arg;
  },
}); 

/*syntaxes such as 5.x, 10.x won't work because the JavaScript compiler cannot be sure whether
  * the dot is for a floating point number or for object property accession.
  * it is safe to use syntaxes such as 5[x], 10[x]
  */
5[x] // [0, 1, 2, 3, 4]
200[x] // [0, 1, ..., 199]

Hopefully this helps someone, I look forward to corrections and code improvements

syntaxes such as 5.x, 10.x won't work because the JavaScript compiler cannot be sure whether the dot is for a floating point number or for object property accession.

To solve the syntax issue, you can write 5..x, but the real issue is that this accesses the property called x instead of using the expression x.

Also, speaking of modifying prototypes, maybe someone would enjoy a proxy treat:

Object.setPrototypeOf(
  Number.prototype,
  new Proxy(Object.prototype, {
    get(t, p, r) {
      if (typeof p === "string") {
        const np = Number(p);
        if (Number.isFinite(np)) {
          const n = Number(r);
          return (function* () {
            if (n < np) {
              for (let i = n; i < np; i++) {
                yield i;
              }
            } else {
              for (let i = n; i > np; i--) {
                yield i;
              }
            }
          })();
        }
      }
      return Reflect.get(t, p, r);
    },
  })
);

console.log([...10[-3]]);
console.log([...0[5]]);
1 Like

That’s cool. 5..x looks like a range, but it’s backwards in this case. 0..5

Unfortunately 0..5 is not valid syntax. But I'm trying to think of some other way like 1..x=100

1 Like

1..to10, 1..to(10), and 1..to[10] are all possible designs. The issue is that they all create string properties which could harm forward compatibility. Number properties are less dangerous in this regard.

1 Like

[...0[5]]

I think that's the closest thing to operator-overloading in JS. I'm not sure if I should feel amazed or horrified, haha (No offense intended! That code is actually a very interesting proof-of-concept. I like it :+1:)

What's this supposed to do, I put this into the terminal and it spat out caught TypeError: 0[5] is not iterable

All these are pretty gross honestly, maybe just a range function would be the way to go :joy: range(0, 5)

Without installing any npm dependencies, I'm pretty happy with

const firstTenSqaures = Array.from({ length: 10 }, (_, i) => i ** 2)

The times I actually need ranges in js is pretty seldom, but still an interesting topic.

@seekr3 Did you run the previous line, which basically hijacks Number.prototype?

1 Like