Categories
arrays javascript range

How to create an array containing 1…N

1907

I’m looking for any alternatives to the below for creating a JavaScript array containing 1 through to N where N is only known at runtime.

var foo = [];

for (var i = 1; i <= N; i++) {
   foo.push(i);
}

To me it feels like there should be a way of doing this without the loop.

7

  • 354

    After reading this entire page, I have come to the conclusion that your own simple for-loop is the simplest, most readable, and least error-prone.

    – Kokodoko

    May 8, 2014 at 16:09

  • If anyone needs something more advanced, I created a node.js lib that does this for numbers, letters, negative/positive ranges, etc. github.com/jonschlinkert/fill-range. It’s used in github.com/jonschlinkert/braces for brace expansion and github.com/jonschlinkert/micromatch for glob patterns

    Jun 9, 2015 at 5:21

  • Another way of doing it can be like this : Array.from({length : 10}, (_, v) => v)

    Aug 25, 2019 at 0:15


  • @SahilGupta Almost. If we want 1 to 10, we need to add 1, e.g. this: Array.from({length : 10}, (_, v) => v+1)

    – Eureka

    Oct 13, 2019 at 21:54

  • Instead of an array, define foo as object {} then add your own indexes with foo[i] = i;

    – SPlatten

    Feb 27, 2020 at 13:42


536

If I get what you are after, you want an array of numbers 1..n that you can later loop through.

If this is all you need, can you do this instead?

var foo = new Array(45); // create an empty array with length 45

then when you want to use it… (un-optimized, just for example)

for(var i = 0; i < foo.length; i++){
  document.write('Item: ' + (i + 1) + ' of ' + foo.length + '<br/>'); 
}

e.g. if you don’t need to store anything in the array, you just need a container of the right length that you can iterate over… this might be easier.

See it in action here: http://jsfiddle.net/3kcvm/

17

  • 6

    impressed you managed to phrase my question better than I could, you are indeed correct as on reflection all I need is an array of numbers that I can later loop through 🙂 Thanks for your answer.

    – Godders

    Sep 19, 2010 at 18:08

  • 189

    @Godders: If this is what you’re looking for, why do you need an array? A simple var n = 45; and then looping from 1..n would do.

    Sep 19, 2010 at 18:33

  • 4

    @Godders – To note, if you want to decrease the size of the array after it is created to length M, simply use foo.length = M — The cut off info is lost. See it in action ==> jsfiddle.net/ACMXp

    Sep 20, 2010 at 2:11

  • 34

    I really dont get why this answer even have upvotes… especially when the OP himself agrees it doesn’t make any sense in a few comments above since he could just have done var n = 45;.

    – plalx

    Nov 4, 2013 at 14:39

  • 101

    @scunliffe: Please note, that new Array(45); does not “create a 45 element array” (in same meaning as [undefined,undefined,..undefined] does). It rather “creates empty array with length = 45” ([undefined x 45]), same as var foo = []; foo.length=45;. That’s why forEach, and map will not apply in this case.

    – tomalec

    Jan 24, 2014 at 14:00

882

You can do so:

var N = 10; 
Array.apply(null, {length: N}).map(Number.call, Number)

result: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

or with random values:

Array.apply(null, {length: N}).map(Function.call, Math.random)

result: [0.7082694901619107, 0.9572225909214467, 0.8586748542729765,
0.8653848143294454, 0.008339877473190427, 0.9911756622605026, 0.8133423360995948, 0.8377588465809822, 0.5577575915958732, 0.16363654541783035]

Explanation

First, note that Number.call(undefined, N) is equivalent to Number(N), which just returns N. We’ll use that fact later.

Array.apply(null, [undefined, undefined, undefined]) is equivalent to Array(undefined, undefined, undefined), which produces a three-element array and assigns undefined to each element.

How can you generalize that to N elements? Consider how Array() works, which goes something like this:

function Array() {
    if ( arguments.length == 1 &&
         'number' === typeof arguments[0] &&
         arguments[0] >= 0 && arguments &&
         arguments[0] < 1 << 32 ) {
        return [ … ];  // array of length arguments[0], generated by native code
    }
    var a = [];
    for (var i = 0; i < arguments.length; i++) {
        a.push(arguments[i]);
    }
    return a;
}

Since ECMAScript 5, Function.prototype.apply(thisArg, argsArray) also accepts a duck-typed array-like object as its second parameter. If we invoke Array.apply(null, { length: N }), then it will execute

function Array() {
    var a = [];
    for (var i = 0; i < /* arguments.length = */ N; i++) {
        a.push(/* arguments[i] = */ undefined);
    }
    return a;
}

Now we have an N-element array, with each element set to undefined. When we call .map(callback, thisArg) on it, each element will be set to the result of callback.call(thisArg, element, index, array). Therefore, [undefined, undefined, …, undefined].map(Number.call, Number) would map each element to (Number.call).call(Number, undefined, index, array), which is the same as Number.call(undefined, index, array), which, as we observed earlier, evaluates to index. That completes the array whose elements are the same as their index.

Why go through the trouble of Array.apply(null, {length: N}) instead of just Array(N)? After all, both expressions would result an an N-element array of undefined elements. The difference is that in the former expression, each element is explicitly set to undefined, whereas in the latter, each element was never set. According to the documentation of .map():

callback is invoked only for indexes of the array which have assigned values; it is not invoked for indexes which have been deleted or which have never been assigned values.

Therefore, Array(N) is insufficient; Array(N).map(Number.call, Number) would result in an uninitialized array of length N.

Compatibility

Since this technique relies on behaviour of Function.prototype.apply() specified in ECMAScript 5, it will not work in pre-ECMAScript 5 browsers such as Chrome 14 and Internet Explorer 9.

13

  • 67

    +1 for cleverness but please note this is orders of magnitude SLOWER than a primitive for loop: jsperf.com/array-magic-vs-for

    – warpech

    Jan 24, 2014 at 13:59


  • 8

    Very clever — probably too so. Exploiting the fact that Function.prototype.call‘s first param is the this object to map directly over Array.prototype.map‘s iterator parameter has a certain brilliance to it.

    Aug 17, 2014 at 22:46

  • 16

    This is really, really clever (borders on abusing JS). The really important insight here is the idiosyncrasy of map on unassigned values, in my opinion. Another version (and possibly slightly clearer, albeit longer) is: Array.apply(null, { length: N }).map(function(element, index) { return index; })

    – Ben Reich

    Oct 22, 2014 at 14:23

  • 7

    @BenReich Even better (in terms of JS abuse levels): Array.apply(null, new Array(N)).map(function(_,i) { return i; }) or, in case of es6 and arrow functions, even shorter: Array.apply(null, new Array(N)).map((_,i) => i)

    – oddy

    Nov 25, 2014 at 0:07


  • 2

    IF this returns an array that starts at 1, it would actually answer the OP’s question

    May 17, 2017 at 3:59

671

Multiple ways using ES6

Using spread operator (...) and keys method

[ ...Array(N).keys() ].map( i => i+1);

Fill/Map

Array(N).fill().map((_, i) => i+1);

Array.from

Array.from(Array(N), (_, i) => i+1)

Array.from and { length: N } hack

Array.from({ length: N }, (_, i) => i+1)

Note about generalised form

All the forms above can produce arrays initialised to pretty much any desired values by changing i+1 to expression required (e.g. i*2, -i, 1+i*2, i%2 and etc). If expression can be expressed by some function f then the first form becomes simply

[ ...Array(N).keys() ].map(f)

Examples:

Array.from({length: 5}, (v, k) => k+1); 
// [1,2,3,4,5]

Since the array is initialized with undefined on each position, the value of v will be undefined

Example showcasing all the forms

let demo= (N) => {
  console.log(
    [ ...Array(N).keys() ].map(( i) => i+1),
    Array(N).fill().map((_, i) => i+1) ,
    Array.from(Array(N), (_, i) => i+1),
    Array.from({ length: N }, (_, i) => i+1)
  )
}

demo(5)

More generic example with custom initialiser function f i.e.

[ ...Array(N).keys() ].map((i) => f(i))

or even simpler

[ ...Array(N).keys() ].map(f)

let demo= (N,f) => {
  console.log(
    [ ...Array(N).keys() ].map(f),
    Array(N).fill().map((_, i) => f(i)) ,
    Array.from(Array(N), (_, i) => f(i)),
    Array.from({ length: N }, (_, i) => f(i))
  )
}

demo(5, i=>2*i+1)

9

  • 6

    Use k++ for arrays starting at 0

    – Borgboy

    Mar 15, 2017 at 1:55

  • 3

    If you want to increment, don’t use k++, use ++k.

    – Alex

    Feb 13, 2018 at 18:42

  • 4

    Beware Array.from is not supported in IE, unless you’re poly-filling it.

    – Lauren

    May 4, 2018 at 21:30

  • 3

    To make the TS compiler happy consider replacing the unused param with lodash: Array.from({ length: 5 }, (_, k) => k + 1);

    Jan 29, 2019 at 12:22

  • 1

    @bluejayke I believe this answer has been edited since I commented, but I was talking specifically about Array.from({length: 5}, (v, k) => k+1);, which does indeed only iterate once.

    – willurd

    Jun 16, 2020 at 3:57