# Provide an easy way to create a new array, filled via a mapping function

**URL:** <https://es.discourse.group/t/provide-an-easy-way-to-create-a-new-array-filled-via-a-mapping-function/1056>\
**Category:** 💡 Ideas\
**Tags:** proposal\
**Created:** [October 25, 2021, 11:54am UTC](https://es.discourse.group/t/provide-an-easy-way-to-create-a-new-array-filled-via-a-mapping-function/1056 "2021-10-25T11:54:38Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![jakearchibald](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/jakearchibald/32/1082_2.png) [@jakearchibald](https://es.discourse.group/u/jakearchibald)\
**Post date:** [October 25, 2021, 11:54am UTC](https://es.discourse.group/t/provide-an-easy-way-to-create-a-new-array-filled-via-a-mapping-function/1056/1 "2021-10-25T11:54:38Z")

</div>

It's pretty common to want to create an array of a given length, and populate it depending on its index. At a really basic level, something like `[1, 2, 3, 4, 5]`.

JS has a lot of nice high-level FP-style array methods, but creating something like `[1, 2, 3, 4, 5]` is surprisingly clunky, or exposes you to some of the less idiomatic parts of JS.

Eg:

```javascript
const result = Array(5).map((_, i) => i + 1);

```

The above doesn't work due to how methods treat 'empty' array entries. A common workaround is:

```javascript
const result = Array(5).fill(0).map((_, i) => i + 1);

```

This still exposes you to the weirdness of 'empty' entries, iterates over the array twice, and leaves the reader with an irrelevant fill value to ignore.

```javascript
const result = [...Array(5)].map((_, i) => i + 1);

```

This avoids the redundant fill value, but still exposes you to the weirdness of 'empty' entries and an extra iteration.

Alternatively:

```javascript
const result = Array.from({ length: 5 }, (_, i) => i + 1);

```

The above avoids the redundant fill value, and the additional iteration, but it feels like a 'trick'. You need to create a value that will cause `Array.from` to create an array of a given length, and treat each entry as non-empty.

This stuff is easy with a plain for-loop of course:

```javascript
const result = [];
for (let i = 0; i < 5; i++) result[i] = i + 1;

```

…but that doesn't fit in with the high-level FP-style methods that already exist.

Should we have something to make this easier, such as:

```javascript
const result = Array.create(5, (i) => i + 1);

```

Although all the examples in this post could be satisfied with some sort of range, I don't think the functionality should be limited to ranges. It should be useful in other cases, eg:

```javascript
function createPoints(input) {
  // input is an array of numbers like [x, y, x, y, x, y]
  return Array.create(input.length / 2, (i) => ({
    x: input[i * 2],
    y: input[i * 2 + 1],
  }));
}

```

---

<div class="post-metadata">

**Author:** ![claudiameadows](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/claudiameadows/32/126_2.png) [@claudiameadows](https://es.discourse.group/u/claudiameadows)\
**Post date:** [October 25, 2021, 12:05pm UTC](https://es.discourse.group/t/provide-an-easy-way-to-create-a-new-array-filled-via-a-mapping-function/1056/2 "2021-10-25T12:05:16Z")

</div>

[GitHub - tc39/proposal-Number.range: A proposal for ECMAScript to add a built-in Number.range()](https://github.com/tc39/proposal-Number.range) is probably what you're looking for.

---

<div class="post-metadata">

**Author:** ![jakearchibald](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/jakearchibald/32/1082_2.png) [@jakearchibald](https://es.discourse.group/u/jakearchibald)\
**Post date:** [October 25, 2021, 12:08pm UTC](https://es.discourse.group/t/provide-an-easy-way-to-create-a-new-array-filled-via-a-mapping-function/1056/3 "2021-10-25T12:08:47Z")

</div>

That's my fault for making the examples overly simple. The times I've needed something like this haven't been limited to ranges. I've added an additional example to clarify.

---

<div class="post-metadata">

**Author:** ![claudiameadows](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/claudiameadows/32/126_2.png) [@claudiameadows](https://es.discourse.group/u/claudiameadows)\
**Post date:** [October 25, 2021, 12:12pm UTC](https://es.discourse.group/t/provide-an-easy-way-to-create-a-new-array-filled-via-a-mapping-function/1056/4 "2021-10-25T12:12:27Z")

</div>

You could still do `Number.range(0, count).map(i => ...).toArray()` when combined with [GitHub - tc39/proposal-iterator-helpers: Methods for working with iterators in ECMAScript](https://github.com/tc39/proposal-iterator-helpers). Is that sufficient?

---

<div class="post-metadata">

**Author:** ![jakearchibald](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/jakearchibald/32/1082_2.png) [@jakearchibald](https://es.discourse.group/u/jakearchibald)\
**Post date:** [October 25, 2021, 12:19pm UTC](https://es.discourse.group/t/provide-an-easy-way-to-create-a-new-array-filled-via-a-mapping-function/1056/5 "2021-10-25T12:19:08Z")

</div>

That seems significantly more complicated than the workarounds currently available. It has a similar problem as `fill(0)` in that it introduces a step that feels redundant. But, on the plus side it doesn't introduce an additional iteration.

```javascript
function createPoints(input) {
  return Number.range(0, input.length / 2)
    .map((i) => ({
      x: input[i * 2],
      y: input[i * 2 + 1],
    }))
    .toArray();
}

// vs

function createPoints(input) {
  return Array.from({ length: input.length / 2 }, (_, i) => ({
    x: input[i * 2],
    y: input[i * 2 + 1],
  }));
}

```

---

<div class="post-metadata">

**Author:** ![jakearchibald](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/jakearchibald/32/1082_2.png) [@jakearchibald](https://es.discourse.group/u/jakearchibald)\
**Post date:** [October 25, 2021, 12:32pm UTC](https://es.discourse.group/t/provide-an-easy-way-to-create-a-new-array-filled-via-a-mapping-function/1056/6 "2021-10-25T12:32:40Z")

</div>

Fwiw, [lodash has `_.times`](https://lodash.com/docs/4.17.15#times), so there's prior art here.

```javascript
function createPoints(input) {
  return _.times(input.length / 2, (i) => ({
    x: input[i * 2],
    y: input[i * 2 + 1],
  }));
}

```

---

<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:** [October 25, 2021, 12:57pm UTC](https://es.discourse.group/t/provide-an-easy-way-to-create-a-new-array-filled-via-a-mapping-function/1056/7 "2021-10-25T12:57:43Z")

</div>

A past proposal is [http://array.build](http://array.build), but the current best practice is indeed the `Array.from` pattern you provided (never use `Array()` or sparse arrays, please, ever)

The number range proposal is another good alternative.

---

<div class="post-metadata">

**Author:** ![jakearchibald](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/jakearchibald/32/1082_2.png) [@jakearchibald](https://es.discourse.group/u/jakearchibald)\
**Post date:** [October 25, 2021, 1:02pm UTC](https://es.discourse.group/t/provide-an-easy-way-to-create-a-new-array-filled-via-a-mapping-function/1056/8 "2021-10-25T13:02:26Z")

</div>

Any idea why the `Array.build` proposal hasn't progressed?

`Array.from({ length }, mappingFn)` is the technique I currently use, but having to create a fake array makes it feel like a hack.

---

<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:** [October 25, 2021, 1:20pm UTC](https://es.discourse.group/t/provide-an-easy-way-to-create-a-new-array-filled-via-a-mapping-function/1056/9 "2021-10-25T13:20:26Z")

</div>

Nobody's brought it forward since the initial pre-ES6 suggestion, afaict.

At this point tho it'd probably need a really persuasive argument showing that removing the `{ length }` is worth the API addition to the language.

---

<div class="post-metadata">

**Author:** ![jakearchibald](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/jakearchibald/32/1082_2.png) [@jakearchibald](https://es.discourse.group/u/jakearchibald)\
**Post date:** [October 25, 2021, 1:31pm UTC](https://es.discourse.group/t/provide-an-easy-way-to-create-a-new-array-filled-via-a-mapping-function/1056/10 "2021-10-25T13:31:37Z")

</div>

I guess we're stuck with the hacky way then 😞

---

<div class="post-metadata">

**Author:** ![theScottyJam](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/thescottyjam/32/616_2.png) [@theScottyJam](https://es.discourse.group/u/theScottyJam)\
**Post date:** [October 25, 2021, 5:20pm UTC](https://es.discourse.group/t/provide-an-easy-way-to-create-a-new-array-filled-via-a-mapping-function/1056/11 "2021-10-25T17:20:14Z")

</div>

> [@ljharb](#):
>
> At this point tho it'd probably need a really persuasive argument showing that removing the `{ length }` is worth the API addition to the language.

It's not about the character count of it though, it's about how we intuitively understand it. I agree that using `Array.from()` with a `{ length }` object requires some unnecessary advance knowledge about the concept of array-like, and it just feels like a hack. I've also often had a need to create an empty array many times, and I'm always hesitant about using `Array.from()`. I'll use it in my own code, since I know what it means, but I usually just use a for loop instead in the code I write at my work, so that I don't have to use such an unnecessarily advanced trick to do something so simple.

However, I would be perfectly happy with the potential future solution @claudiameadows demonstrated, of using the iterator helpers proposal with a range.

---

<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:** [October 25, 2021, 5:34pm UTC](https://es.discourse.group/t/provide-an-easy-way-to-create-a-new-array-filled-via-a-mapping-function/1056/12 "2021-10-25T17:34:57Z")

</div>

To be clear, I would love to see something like Array.build added to the language; I just don't think I could make a persuasive argument for it to the committee.

---

<div class="post-metadata">

**Author:** ![bakkot](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/bakkot/32/22_2.png) [@bakkot](https://es.discourse.group/u/bakkot)\
**Post date:** [October 25, 2021, 8:26pm UTC](https://es.discourse.group/t/provide-an-easy-way-to-create-a-new-array-filled-via-a-mapping-function/1056/13 "2021-10-25T20:26:58Z")

</div>

I think it's worth a shot! New APIs don't have nearly as high a bar as new syntax.

---

<div class="post-metadata">

**Author:** ![aclaymore](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/aclaymore/32/501_2.png) [@aclaymore](https://es.discourse.group/u/aclaymore)\
**Post date:** [October 25, 2021, 8:40pm UTC](https://es.discourse.group/t/provide-an-easy-way-to-create-a-new-array-filled-via-a-mapping-function/1056/14 "2021-10-25T20:40:02Z")

</div>

Duplicate thread to tie together [Array.create](https://es.discourse.group/t/array-create/628)

---

<div class="post-metadata">

**Author:** ![aleen42](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/aleen42/32/461_2.png) [@aleen42](https://es.discourse.group/u/aleen42)\
**Post date:** [October 26, 2021, 5:58am UTC](https://es.discourse.group/t/provide-an-easy-way-to-create-a-new-array-filled-via-a-mapping-function/1056/15 "2021-10-26T05:58:13Z")

</div>

Similar to [`_.times`](https://lodash.com/docs/4.17.15#times)

---

<div class="post-metadata">

**Author:** ![theScottyJam](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/thescottyjam/32/616_2.png) [@theScottyJam](https://es.discourse.group/u/theScottyJam)\
**Post date:** [October 26, 2021, 2:18pm UTC](https://es.discourse.group/t/provide-an-easy-way-to-create-a-new-array-filled-via-a-mapping-function/1056/16 "2021-10-26T14:18:03Z")

</div>

Alright, well perhaps let try brainstorming a couple of options here to see what we like best.

Some of these solutions let you optionally provide a mapping function. Other ones require you to use .map() afterwards.

```javascript
Array.create(length, mappingFn?) // Original idea
Array.fromLength(length, mappingFn?) // Also works
Array.build(length, mapFn?) // From the Array.build proposal

// Fills with undefined, and requires people to use .map() afterwards.
// Does not take a mappingFn
// Can be thought of as a direct replacement for new Array(length)
Array.fromLength(length)

Array.prototype.repeat(length) // e.g. [2].repeat(3) == [2, 2, 2] -- paralells with string.repeat(). Similar to array multiplication in python.
Array.prototype.repeat(length, mapFn?)

// -- Functions that pre-fill the array with other stuff -- //

Array.fromRange(start?, end) // e.g. Array.fromRange(2, 5) == [2, 3, 4]
Array.filled(length, value?) // e.g. Array.filled(2, null) == [null, null], value defaults to undefined

```

These are just the solutions I could come up with (or that others have come up with already). Usability-wise, solutions that don't include a mapping function should work just as well, because you can just use .map() afterwards, however, I presume it will be less optimized as engines will have to iterate a second time over the values as they create the array.

---

<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:** [October 26, 2021, 2:50pm UTC](https://es.discourse.group/t/provide-an-easy-way-to-create-a-new-array-filled-via-a-mapping-function/1056/17 "2021-10-26T14:50:55Z")

</div>

fromLength with a mapping function seems simplest to me. "repeat" sounds like a horrifyingly quick way to generate a memory error :-p

---

<div class="post-metadata">

**Author:** ![theScottyJam](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/thescottyjam/32/616_2.png) [@theScottyJam](https://es.discourse.group/u/theScottyJam)\
**Post date:** [October 26, 2021, 3:21pm UTC](https://es.discourse.group/t/provide-an-easy-way-to-create-a-new-array-filled-via-a-mapping-function/1056/18 "2021-10-26T15:21:32Z")

</div>

I do also like how .fromLength() gives a little more context about what the parameters do (at least, what the first parameter would do). Array.build() and Array.create() doesn't tell you anything about what its parameters do.

---

<div class="post-metadata">

**Author:** ![aclaymore](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/aclaymore/32/501_2.png) [@aclaymore](https://es.discourse.group/u/aclaymore)\
**Post date:** [October 26, 2021, 7:52pm UTC](https://es.discourse.group/t/provide-an-easy-way-to-create-a-new-array-filled-via-a-mapping-function/1056/19 "2021-10-26T19:52:01Z")

</div>

`Array.withLength` ?

EDIT: I already don’t like this 😝

---

<div class="post-metadata">

**Author:** ![bergus](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/bergus/32/152_2.png) [@bergus](https://es.discourse.group/u/bergus)\
**Post date:** [October 26, 2021, 8:50pm UTC](https://es.discourse.group/t/provide-an-easy-way-to-create-a-new-array-filled-via-a-mapping-function/1056/20 "2021-10-26T20:50:06Z")

</div>

I guess it would be superfluous once the [`Number.range` proposal](https://github.com/tc39/proposal-Number.range) got through. It would offer not just

```javascript
const result = Number.range(0, count).map(i => i+1).toArray();

```

but also

```javascript
const result = Array.from(Number.range(0, count).map(i => i+1));
const result = Array.from(Number.range(0, count), i => i+1);

```

where I don't see much advantage of combining `from` and `range` into a single `fromRange` method.

[Next page](https://es.discourse.group/t/provide-an-easy-way-to-create-a-new-array-filled-via-a-mapping-function/1056.md?page=2)
