javascript - How to create an array containing 1...N

ID : 613

viewed : 75

Tags : javascriptarraysjavascript

Top 5 Answer for javascript - How to create an array containing 1...N

vote vote

96

In ES6 using Array from() and keys() methods.

Array.from(Array(10).keys()) //=> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 

Shorter version using spread operator.

[...Array(10).keys()] //=> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 

Start from 1 by passing map function to Array from(), with an object with a length property:

Array.from({length: 10}, (_, i) => i + 1) //=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] 
vote vote

82

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.

vote vote

79

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)

vote vote

63

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/

vote vote

60

Arrays innately manage their lengths. As they are traversed, their indexes can be held in memory and referenced at that point. If a random index needs to be known, the indexOf method can be used.


This said, for your needs you may just want to declare an array of a certain size:

var foo = new Array(N);   // where N is a positive integer  /* this will create an array of size, N, primarily for memory allocation,     but does not create any defined values     foo.length                                // size of Array    foo[ Math.floor(foo.length/2) ] = 'value' // places value in the middle of the array */ 


ES6

Spread

Making use of the spread operator (...) and keys method, enables you to create a temporary array of size N to produce the indexes, and then a new array that can be assigned to your variable:

var foo = [ ...Array(N).keys() ]; 

Fill/Map

You can first create the size of the array you need, fill it with undefined and then create a new array using map, which sets each element to the index.

var foo = Array(N).fill().map((v,i)=>i); 

Array.from

This should be initializing to length of size N and populating the array in one pass.

Array.from({ length: N }, (v, i) => i) 



In lieu of the comments and confusion, if you really wanted to capture the values from 1..N in the above examples, there are a couple options:

  1. if the index is available, you can simply increment it by one (e.g., ++i).
  2. in cases where index is not used -- and possibly a more efficient way -- is to create your array but make N represent N+1, then shift off the front.

    So if you desire 100 numbers:

    let arr; (arr=[ ...Array(101).keys() ]).shift() 




Top 3 video Explaining javascript - How to create an array containing 1...N

Related QUESTION?