Skip to content

Instantly share code, notes, and snippets.

@rwaldron
Last active January 21, 2021 18:18
Show Gist options
  • Star 8 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rwaldron/11186883 to your computer and use it in GitHub Desktop.
Save rwaldron/11186883 to your computer and use it in GitHub Desktop.
Array.build(length, mapFn = undefined)

Array.build

Originally conceived by Dave Herman, based on: http://docs.racket-lang.org/reference/pairs.html#%28def._%28%28lib._racket%2Fprivate%2Flist..rkt%29._build-list%29%29

Rationale

There is no easy way to create an array, of user defined length, containing values that are not undefined. Easily build range functionality ontop.

Prior Art

> (build-list 10 values)
'(0 1 2 3 4 5 6 7 8 9)

> (build-list 5 (lambda (x) (* x x)))
'(0 1 4 9 16)
> Array.new(10) {|index| index}
=> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

> Array.new(5) {|n| n * n}
=> [0, 1, 4, 9, 16]

Array.build(length, mapfn = undefined)

When the build method is called with arguments length and optional argument mapfn the following steps are taken:

  1. Let len be ToLength(length).
  2. Let C be the this value.
  3. If IsConstructor(C) is true, then
    1. Let A be the result of calling the [[Construct]] internal method of C with an argument list containing the single item len.
  4. Else,
    1. Let A be ArrayCreate(len).
  5. Let k be 0.
  6. If mapfn is undefined, then let mapping be false.
  7. Else,
    1. If IsCallable(_mapfn_) is false, throw a TypeError exception.
    2. Let mapping be true.
  8. Repeat, while k < len
    1. If mapping is true, then
      1. Let mappedValue be the result of calling the [[Call]] internal method of mapfn with A as thisArgument and a List containing k as argumentsList.
      2. ReturnIfAbrupt(mappedValue).
    2. Else,
      1. Let mappedValue be k.
    3. Let Pk be ToString(k).
    4. Let defineStatus be CreateDataPropertyOrThrow(A, Pk, mappedValue).
    5. ReturnIfAbrupt(defineStatus).
    6. Increase k by 1.
  9. Let putStatus be Put(A, "length", len, true).
  10. ReturnIfAbrupt(putStatus).
  11. Return A.

Examples:

> Array.build(10);
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

> Array.build(5, n => n * n);
[0, 1, 4, 9, 16]
function range(lower, upper) {
  return Array.build(upper - lower, n => n + lower);
}

range(9, 18);

[9, 10, 11, 12, 13, 14, 15, 16, 17];
function isConstructor(C) {
try {
new C();
return true;
} catch (e) {
return false;
}
}
Array.build = function(length, mapFn) {
var len = length >>> 0;
var C = this;
var mapping = false;
var k = 0;
var A;
if (isConstructor(C)) {
A = new C(length);
} else {
A = new Array(length);
}
if (typeof mapFn === "function") {
mapping = true;
}
while (k < len) {
A[k] = mapping ? mapFn.call(A, k) : k;
k++;
}
return A;
};
@caub
Copy link

caub commented May 27, 2018

Could we re-propose it to ECMA-proposals? since it makes things really simpler

- Array.from({length: n}, (_, i) => ({id: `foo${i}`}))
+ Array.build(n, i => ({id: `foo${i}`}))

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment