What is the most efficient way to create an arbitrary length zero filled array in JavaScript?
ES6 introduces Array.prototype.fill
. It can be used like this:
new Array(len).fill(0);
Not sure if it's fast, but I like it because it's short and self-describing.
It's still not in IE (check compatibility), but there's a polyfill available.
new Array(len)
is painfully slow. (arr = []).length = len; arr.fill(0);
is about the fastest solution ive seen anywhere... or at least tied –
Rhododendron arr = Array(n)
and (arr = []).length = n
behave identically according to the spec. In some implementations one could be faster, but I don't think there is a big difference. –
Glynisglynn (arr = []).length = len; arr.fill(0);
is much faster. It does seem tho, certain sizes in certain environments it is faster to use new Array
. But after all the design and speed testing is done, that is so rare for me. –
Rhododendron new Array(len)
is painfully slow. –
Glynisglynn (arr = []).length = 1000;
against arr = new Array(1000);
speed test it in both Chrome and FF... the new
is terribly slow. Now, for array lengths smaller.. say < 50 or there abouts... then new Array()
does seem to perform better. But.. –
Rhododendron arr.fill(0)
... everything sorta changes. Now, using new Array()
is faster in most cases except when you get to array sizes > 100000... Then you can start to see the speed increase again. But if you don't actually have to prefill it with zeros and can use standard falisy of empty arrays. Then (arr = []).length = x
is crazy fast in my test cases most of the time. –
Rhododendron new Array(5).forEach(val => console.log('hi'));
vs new Array(5).fill(undefined).forEach(val => console.log('hi'));
. –
Sula fill()
being quite a bit slower than a for loop when the array gets really big: jsperf.com/zero-filling-large-arrays And no significant difference between new Array(n)
and a = []; a.length = n
–
Beauty Although this is an old thread, I wanted to add my 2 cents to it. Not sure how slow/fast this is, but it's a quick one liner. Here is what I do:
If I want to pre-fill with a number:
Array.apply(null, Array(5)).map(Number.prototype.valueOf,0);
// [0, 0, 0, 0, 0]
If I want to pre-fill with a string:
Array.apply(null, Array(3)).map(String.prototype.valueOf,"hi")
// ["hi", "hi", "hi"]
Other answers have suggested:
new Array(5+1).join('0').split('')
// ["0", "0", "0", "0", "0"]
but if you want 0 (the number) and not "0" (zero inside a string), you can do:
new Array(5+1).join('0').split('').map(parseFloat)
// [0, 0, 0, 0, 0]
Array.apply(null, new Array(5)).map(...)
? Cause simply doing (new Array(5)).map(...) won't work as the spec tells –
Atwood new
) When you do Array(5)
you're creating an object that kinda looks like this: { length: 5, __proto__: Array.prototype }
- try console.dir( Array(5) )
. Notice that it doesn't have any properties 0
, 1
, 2
, etc. But when you apply
that unto the Array
constructor, it's like saying Array(undefined, undefined, undefined, undefined, undefined)
. And you get an object that kinda looks like { length: 5, 0: undefined, 1: undefined...}
. map
works on the properties 0
,1
, etc. which is why your example doesn't work, but when you use apply
it does. –
Risibility null
as constructor function execution context doesn't really matter there, it could as well be {}
or []
? –
Atwood .apply
is actually what you want the this
to be. For these purposes the this
doesn't matter - we only really care about the parameter spreading "feature" of .apply
- so it can be any value. I like null
because it's cheap, you probably don't want to use {}
or []
since you'd be instantiating an object for no reason. –
Risibility new Array(5).fill(0);
from ES2015 to this beautiful answer –
Mastectomy Array.apply(null, Array(3))
you can also use Array.apply(null, { length: 3 })
, which is still a tiny bit faster in FF (no difference in Chrome, tough): jsperf.com/array-apply-length –
Malamud Number.prototype.valueOf,0
with just function() {return 0}
seems a bit faster. –
Disfrock Array(...Array(5))
to create array of undefined
s –
Laurenelaurens Array.apply(null, Array(1000000))
VM3904:1 Uncaught RangeError: Maximum call stack size exceeded at <anonymous>:1:7
–
Stagemanage In short
Fastest solution:
let a = new Array(n); for (let i=0; i<n; ++i) a[i] = 0;
Shortest (handy) solution (3x slower for small arrays, slightly slower for big (slowest on Firefox))
Array(n).fill(0)
Details
Today 2020.06.09 I perform tests on macOS High Sierra 10.13.6 on browsers Chrome 83.0, Firefox 77.0, and Safari 13.1. I test chosen solutions for two test cases
- small array - with 10 elements - you can perform test HERE
- big arrays - with 1M elements - you can perform test HERE
Conclusions
- solution based on
new Array(n)+for
(N) is fastest solution for small arrays and big arrays (except Chrome but still very fast there) and it is recommended as fast cross-browser solution - solution based on
new Float32Array(n)
(I) returns non typical array (e.g. you cannot callpush(..)
on it) so I not compare its results with other solutions - however this solution is about 10-20x faster than other solutions for big arrays on all browsers - solutions based on
for
(L,M,N,O) are fast for small arrays - solutions based on
fill
(B,C) are fast on Chrome and Safari but surprisingly slowest on Firefox for big arrays. They are medium fast for small arrays - solution based on
Array.apply
(P) throws error for big arraysfunction P(n) { return Array.apply(null, Array(n)).map(Number.prototype.valueOf,0); } try { P(1000000); } catch(e) { console.error(e.message); }
Code and example
Below code presents solutions used in measurements
function A(n) {
return [...new Array(n)].fill(0);
}
function B(n) {
return new Array(n).fill(0);
}
function C(n) {
return Array(n).fill(0);
}
function D(n) {
return Array.from({length: n}, () => 0);
}
function E(n) {
return [...new Array(n)].map(x => 0);
}
// arrays with type
function F(n) {
return Array.from(new Int32Array(n));
}
function G(n) {
return Array.from(new Float32Array(n));
}
function H(n) {
return Array.from(new Float64Array(n)); // needs 2x more memory than float32
}
function I(n) {
return new Float32Array(n); // this is not typical array
}
function J(n) {
return [].slice.apply(new Float32Array(n));
}
// Based on for
function K(n) {
let a = [];
a.length = n;
let i = 0;
while (i < n) {
a[i] = 0;
i++;
}
return a;
}
function L(n) {
let a=[]; for(let i=0; i<n; i++) a[i]=0;
return a;
}
function M(n) {
let a=[]; for(let i=0; i<n; i++) a.push(0);
return a;
}
function N(n) {
let a = new Array(n); for (let i=0; i<n; ++i) a[i] = 0;
return a;
}
function O(n) {
let a = new Array(n); for (let i=n; i--;) a[i] = 0;
return a;
}
// other
function P(n) {
return Array.apply(null, Array(n)).map(Number.prototype.valueOf,0);
}
function Q(n) {
return "0".repeat( n ).split("").map( parseFloat );
}
function R(n) {
return new Array(n+1).join('0').split('').map(parseFloat)
}
// ---------
// TEST
// ---------
[A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R].forEach(f => {
let a = f(10);
console.log(`${f.name} length=${a.length}, arr[0]=${a[0]}, arr[9]=${a[9]}`)
});
This snippets only present used codes
Example results for Chrome:
let a=[]; for(i=n;i--;) a.push(0);
- but it is 4x slower than fill(0)
- so I will even not update the picture witch that case. –
Internecine for-loop
(N) was only 1.835 faster than .fill
(C) in Safari, and it's interesting to note that when I ran it now, 6 months later, the difference has gone down to only 1.456x. So for Safari, the fastest solution (N) is only 45% faster than the shortest and simplest version. Moral: Stick with the shortest and simplest versions (for most if not all cases). It saves expensive developer time, through being faster to read, easier to maintain, and also pays off more and more as time and CPU speeds increase, without extra maintenance. –
Reinke Elegant way to fill an array with precomputed values
Here is another way to do it using ES6 that nobody has mentioned so far:
> Array.from(Array(3), () => 0)
< [0, 0, 0]
It works by passing a map function as the second parameter of Array.from
.
In the example above, the first parameter allocates an array of 3 positions filled with the value undefined
and then the lambda function maps each one of them to the value 0
.
Although Array(len).fill(0)
is shorter, it doesn't work if you need to fill the array by doing some computation first (I know the question didn't ask for it, but a lot of people end up here looking for this).
For instance, if you need an array with 10 random numbers:
> Array.from(Array(10), () => Math.floor(10 * Math.random()))
< [3, 6, 8, 1, 9, 3, 0, 6, 7, 1]
It's more concise (and elegant) than the equivalent:
const numbers = Array(10);
for (let i = 0; i < numbers.length; i++) {
numbers[i] = Math.round(10 * Math.random());
}
This method can also be used to generate sequences of numbers by taking advantage of the index parameter provided in the callback:
> Array.from(Array(10), (d, i) => i)
< [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
Bonus answer: fill an array using String repeat()
Since this answer is getting a good deal of attention, I also wanted to show this cool trick. Although not as useful as my main answer, will introduce the still not very known, but very useful String repeat()
method. Here's the trick:
> "?".repeat(10).split("").map(() => Math.floor(10 * Math.random()))
< [5, 6, 3, 5, 0, 8, 2, 7, 4, 1]
Cool, huh? repeat()
is a very useful method to create a string that is the repetition of the original string a certain number of times. After that, split()
creates an array for us, which is then map()
ped to the values we want. Breaking it down in steps:
> "?".repeat(10)
< "??????????"
> "?".repeat(10).split("")
< ["?", "?", "?", "?", "?", "?", "?", "?", "?", "?"]
> "?".repeat(10).split("").map(() => Math.floor(10 * Math.random()))
< [5, 6, 3, 5, 0, 8, 2, 7, 4, 1]
repeat
trick is definitely not wanted in production, Array.from()
is perfectly fine :-) –
Crossbones Array(N)
pre-allocates N cells, which isn't necessarily true, otherwise Array(2**32 - 1)
would be allocating more than all my RAM. Browser engines likely use various heuristics to determine whether or not to allocate in advance or use a sparse array. In any case, you can use Array.from({ length: N }, callback)
instead. –
Wembley The already mentioned ES 6 fill method takes care of this nicely. Most modern desktop browsers already support the required Array prototype methods as of today (Chromium, FF, Edge and Safari) [1]. You can look up details on MDN. A simple usage example is
a = new Array(10).fill(0);
Given the current browser support you should be cautious to use this unless you are sure your audience uses modern Desktop browsers.
a = Array(10).fill(null).map(() => { return []; });
–
Spiegelman a = Array(10).fill(0).map( _ => [] );
–
Manos Note added August 2013, updated February 2015: The answer below from 2009 relates to JavaScript's generic Array
type. It doesn't relate to the newer typed arrays defined in ES2015 [and available now in many browsers], like Int32Array
and such. Also note that ES2015 adds a fill
method to both Arrays and typed arrays, which is likely to be the most efficient way to fill them...
Also, it can make a big difference to some implementations how you create the array. Chrome's V8 engine, in particular, tries to use a highly-efficient, contiguous-memory array if it thinks it can, shifting to the object-based array only when necessary.
With most languages, it would be pre-allocate, then zero-fill, like this:
function newFilledArray(len, val) {
var rv = new Array(len);
while (--len >= 0) {
rv[len] = val;
}
return rv;
}
But, JavaScript arrays aren't really arrays, they're key/value maps just like all other JavaScript objects, so there's no "pre-allocate" to do (setting the length doesn't allocate that many slots to fill), nor is there any reason to believe that the benefit of counting down to zero (which is just to make the comparison in the loop fast) isn't outweighed by adding the keys in reverse order when the implementation may well have optimized their handling of the keys related to arrays on the theory you'll generally do them in order.
In fact, Matthew Crumley pointed out that counting down is markedly slower on Firefox than counting up, a result I can confirm — it's the array part of it (looping down to zero is still faster than looping up to a limit in a var). Apparently adding the elements to the array in reverse order is a slow op on Firefox. In fact, the results vary quite a bit by JavaScript implementation (which isn't all that surprising). Here's a quick and dirty test page (below) for browser implementations (very dirty, doesn't yield during tests, so provides minimal feedback and will run afoul of script time limits). I recommend refreshing between tests; FF (at least) slows down on repeated tests if you don't.
The fairly complicated version that uses Array#concat is faster than a straight init on FF as of somewhere between 1,000 and 2,000 element arrays. On Chrome's V8 engine, though, straight init wins out every time...
Here's a test:
const tests = [
{
name: "downpre",
total: 0,
desc: "Count down, pre-decrement",
func: makeWithCountDownPre
},
{
name: "downpost",
total: 0,
desc: "Count down, post-decrement",
func: makeWithCountDownPost
},
{
name: "up",
total: 0,
desc: "Count up (normal)",
func: makeWithCountUp
},
{
name: "downandup",
total: 0,
desc: "Count down (for loop) and up (for filling)",
func: makeWithCountDownArrayUp
},
{
name: "concat",
total: 0,
desc: "Concat",
func: makeWithConcat
}
];
const q = sel => document.querySelector(sel);
let markup = "";
for (const {name, desc} of tests) {
markup += `
<div><input type="checkbox" id="chk_${name}" checked>
<label for="chk_${name}">${desc}</label></div>`;
}
q("#checkboxes").innerHTML = markup;
q("#btnTest").addEventListener("click", btnTestClick);
function btnTestClick() {
// Clear log
q("#log").innerHTML = "Testing...";
// Show running
q("#btnTest").disabled = true;
// Run after a pause while the browser updates display
setTimeout(btnTestClickPart2, 0);
}
function btnTestClickPart2() {
try {
runTests();
} catch (e) {
log(`Exception: ${e.message}`);
}
// Re-enable the button
q("#btnTest").disabled = false;
}
function getNumField(name) {
const val = q("#" + name).value.trim();
const num = /^\d+$/.test(val) ? parseInt(val) : NaN;
if (isNaN(num) || num <= 0) {
throw new Error(`Invalid ${name} value ${JSON.stringify(val)}`);
}
return num;
}
function runTests() {
try {
// Clear log
q("#log").innerHTML = "";
const runCount = getNumField("loops");
const length = getNumField("length");
// Do it (we run runCount + 1 times, first time is a warm up)
for (let counter = 0; counter <= runCount; ++counter) {
for (const test of tests) {
if (q("#chk_" + test.name).checked) {
const start = Date.now();
const a = test.func(length);
const time = Date.now() - start;
if (counter == 0) {
// Don't count (warm up), but do check the algorithm works
const invalid = validateResult(a, length);
if (invalid) {
log(`<span class=error>FAILURE</span> with test ${test.name}: ${invalid}`);
return;
}
} else {
// Count this one
log(`#${counter}: ${test.desc}: ${time}ms`);
test.total += time;
}
}
}
}
for (const test of tests) {
if (q("#chk_" + test.name).checked) {
test.avg = test.total / runCount;
if (typeof lowest != "number" || lowest > test.avg) {
lowest = test.avg;
}
}
}
let results =
"<p>Results:" +
"<br>Length: " + length +
"<br>Loops: " + runCount +
"</p>";
for (const test of tests) {
if (q("#chk_" + test.name).checked) {
results +=
`<p ${lowest == test.avg ? " class=winner" : ""}>${test.desc}, average time: ${test.avg}ms</p>`;
}
}
results += "<hr>";
q("#log").insertAdjacentHTML("afterbegin", results);
} catch (e) {
log(e.message);
return;
}
}
function validateResult(a, length) {
if (a.length != length) {
return "Length is wrong";
}
for (let n = length - 1; n >= 0; --n) {
if (a[n] != 0) {
return "Index " + n + " is not zero";
}
}
return undefined;
}
function makeWithCountDownPre(len) {
const a = new Array(len);
while (--len >= 0) {
a[len] = 0;
}
return a;
}
function makeWithCountDownPost(len) {
const a = new Array(len);
while (len-- > 0) {
a[len] = 0;
}
return a;
}
function makeWithCountUp(len) {
const a = new Array(len);
for (let i = 0; i < len; ++i) {
a[i] = 0;
}
return a;
}
function makeWithCountDownArrayUp(len) {
const a = new Array(len);
let i = 0;
while (--len >= 0) {
a[i++] = 0;
}
return a;
}
function makeWithConcat(len) {
if (len == 0) {
return [];
}
let a = [0];
let currlen = 1;
while (currlen < len) {
const rem = len - currlen;
if (rem < currlen) {
a = a.concat(a.slice(0, rem));
} else {
a = a.concat(a);
}
currlen = a.length;
}
return a;
}
function log(msg) {
const p = document.createElement("p");
p.textContent = msg;
q("#log").appendChild(p);
}
body {
font-family: sans-serif;
}
#log p {
margin: 0;
padding: 0;
}
.error {
color: red;
}
.winner {
color: green;
}
<div>
<label for='txtLength'>Length:</label><input type='text' id='length' value='1000'>
<br><label for='txtLoops'>Loops:</label><input type='text' id='loops' value='100000'>
<div id='checkboxes'></div>
<br><input type='button' id='btnTest' value='Test'>
<hr>
<div id='log'></div>
</div>
If you use ES6, you can use Array.from() like this:
Array.from({ length: 3 }, () => 0);
//[0, 0, 0]
Has the same result as
Array.from({ length: 3 }).map(() => 0)
//[0, 0, 0]
Because
Array.from({ length: 3 })
//[undefined, undefined, undefined]
By default Uint8Array
, Uint16Array
and Uint32Array
classes keep zeros as its values, so you don't need any complex filling techniques, just do:
var ary = new Uint8Array(10);
all elements of array ary
will be zeros by default.
Array.isArray(ary)
is false
. The length is also read-only so you cannot push new items to it as with ary.push
–
Airt 0
as their default value. –
Beast Array.from(new Uint8Array(10))
will provide a normal array. –
Omdurman Array(n).fill(0)
in Chrome if what you really need is a JS Array. If you can use a TypedArray, this is much faster even than .fill(0)
, though, especially if you can use the default initializer value of 0
. There doesn't seem to be a constructor that takes a fill-value and length, the way C++ std::vector
has. It seems for any non-zero value you have to construct a zeroed TypedArray and then fill it. :/ –
Shores function makeArrayOf(value, length) {
var arr = [], i = length;
while (i--) {
arr[i] = value;
}
return arr;
}
makeArrayOf(0, 5); // [0, 0, 0, 0, 0]
makeArrayOf('x', 3); // ['x', 'x', 'x']
Note that while
is usually more efficient than for-in
, forEach
, etc.
i
local variable extraneous? length
is passed by value so you should be able to decrement it directly. –
Fierce arr[i] = value
). It's much faster to loop through from beginning to end and use arr.push(value)
. It's annoying, because I prefer your method. –
Evangelineevangelism using object notation
var x = [];
zero filled? like...
var x = [0,0,0,0,0,0];
filled with 'undefined'...
var x = new Array(7);
obj notation with zeros
var x = [];
for (var i = 0; i < 10; i++) x[i] = 0;
As a side note, if you modify Array's prototype, both
var x = new Array();
and
var y = [];
will have those prototype modifications
At any rate, I wouldn't be overly concerned with the efficiency or speed of this operation, there are plenty of other things that you will likely be doing that are far more wasteful and expensive than instanciating an array of arbitrary length containing zeros.
null
s in this array - var x = new Array(7);
–
Stenosis new Array(7)
does not create an array "filled with undefined". It creates an empty array with length 7. –
Canady (new Array(10)).fill(0)
. –
Heiduc Array(10).fill(0)
is equivalent and shorter. For proof that Array(10)
is equivalent to new Array(10)
, see https://mcmap.net/q/20993/-array-vs-new-array –
Tiptop I've tested all combinations of pre-allocating/not pre-allocating, counting up/down, and for/while loops in IE 6/7/8, Firefox 3.5, Chrome, and Opera.
The functions below was consistently the fastest or extremely close in Firefox, Chrome, and IE8, and not much slower than the fastest in Opera and IE 6. It's also the simplest and clearest in my opinion. I've found several browsers where the while loop version is slightly faster, so I'm including it too for reference.
function newFilledArray(length, val) {
var array = [];
for (var i = 0; i < length; i++) {
array[i] = val;
}
return array;
}
or
function newFilledArray(length, val) {
var array = [];
var i = 0;
while (i < length) {
array[i++] = val;
}
return array;
}
var array = []
declaration into the first part of the for loop actually, separated by only a comma. –
Hydrophobic length
value already given so that it's not constantly changing. Brought a 1 million length array of zero's from 40ms to 8 on my machine. –
Vitalis for (i = 0, array = []; i < length; ++i) array[i] = val;
.. Fewer blocks? ... anyhow, also... if I set the array.length
of the new array to the length.. i seem to get another 10%-15% speed increase in FF... in Chrome, it seems to double the speed -> var i, array = []; array.length = length; while(i < length) array[i++] = val;
(was still faster if I left it as a for
loop... but the init is no longer needed, so the while
is seemly faster on this version) –
Rhododendron ES6 solution:
[...new Array(5)].map(x => 0); // [0, 0, 0, 0, 0]
const arr = Array.from({ length: 10 }).fill(0);
console.log(arr)
If you need to create many zero filled arrays of different lengths during the execution of your code, the fastest way I've found to achieve this is to create a zero array once, using one of the methods mentioned on this topic, of a length which you know will never be exceeded, and then slice that array as necessary.
For example (using the function from the chosen answer above to initialize the array), create a zero filled array of length maxLength, as a variable visible to the code that needs zero arrays:
var zero = newFilledArray(maxLength, 0);
Now slice this array everytime you need a zero filled array of length requiredLength < maxLength:
zero.slice(0, requiredLength);
I was creating zero filled arrays thousands of times during execution of my code, this speeded up the process tremendously.
function zeroFilledArray(size) {
return new Array(size + 1).join('0').split('');
}
new Array(size+1).join("x").split("x").map(function() { return 0; })
to get actual numbers –
Olivia new Array(size+1).join('0').split('').map(Number)
–
Pearl Using lodash or underscore
_.range(0, length - 1, 0);
Or if you have an array existing and you want an array of the same length
array.map(_.constant(0));
_.range(0, length, 0)
, I believe. Lodash is exclusive of end value –
Heckelphone I have nothing against:
Array.apply(null, Array(5)).map(Number.prototype.valueOf,0);
new Array(5+1).join('0').split('').map(parseFloat);
suggested by Zertosh, but in a new ES6 array extensions allow you to do this natively with fill
method. Now IE edge, Chrome and FF supports it, but check the compatibility table
new Array(3).fill(0)
will give you [0, 0, 0]
. You can fill the array with any value like new Array(5).fill('abc')
(even objects and other arrays).
On top of that you can modify previous arrays with fill:
arr = [1, 2, 3, 4, 5, 6]
arr.fill(9, 3, 5) # what to fill, start, end
which gives you: [1, 2, 3, 9, 9, 6]
To create an all new Array
new Array(arrayLength).fill(0);
To add some values at the end of an existing Array
[...existingArray, ...new Array(numberOfElementsToAdd).fill(0)]
Example
//**To create an all new Array**
console.log(new Array(5).fill(0));
//**To add some values at the end of an existing Array**
let existingArray = [1,2,3]
console.log([...existingArray, ...new Array(5).fill(0)]);
The way I usually do it (and is amazing fast) is using Uint8Array
. For example, creating a zero filled vector of 1M elements:
var zeroFilled = [].slice.apply(new Uint8Array(1000000))
I'm a Linux user and always have worked for me, but once a friend using a Mac had some non-zero elements. I thought his machine was malfunctioning, but still here's the safest way we found to fix it:
var zeroFilled = [].slice.apply(new Uint8Array(new Array(1000000))
Edited
Chrome 25.0.1364.160
- Frederik Gottlieb - 6.43
- Sam Barnum - 4.83
- Eli - 3.68
- Joshua 2.91
- Mathew Crumley - 2.67
- bduran - 2.55
- Allen Rice - 2.11
- kangax - 0.68
- Tj. Crowder - 0.67
- zertosh - ERROR
Firefox 20.0
- Allen Rice - 1.85
- Joshua - 1.82
- Mathew Crumley - 1.79
- bduran - 1.37
- Frederik Gottlieb - 0.67
- Sam Barnum - 0.63
- Eli - 0.59
- kagax - 0.13
- Tj. Crowder - 0.13
- zertosh - ERROR
Missing the most important test (at least for me): the Node.js one. I suspect it close to Chrome benchmark.
As of ECMAScript2016, there is one clear choice for large arrays.
Since this answer still shows up near the top on google searches, here's an answer for 2017.
Here's a current jsbench with a few dozen popular methods, including many proposed up to now on this question. If you find a better method please add, fork and share.
I want to note that there is no true most efficient way to create an arbitrary length zero filled array. You can optimize for speed, or for clarity and maintainability - either can be considered the more efficient choice depending on the needs of the project.
When optimizing for speed, you want to: create the array using literal syntax; set the length, initialize iterating variable, and iterate through the array using a while loop. Here's an example.
const arr = [];
arr.length = 120000;
let i = 0;
while (i < 120000) {
arr[i] = 0;
i++;
}
Another possible implementation would be:
(arr = []).length = n;
let i = 0;
while (i < n) {
arr[i] = 0;
i++;
}
But I strongly discourage using this second implantation in practice as it's less clear and doesn't allow you to maintain block scoping on your array variable.
These are significantly faster than filling with a for loop, and about 90% faster than the standard method of
const arr = Array(n).fill(0);
But this fill method is still the most efficient choice for smaller arrays due to it's clarity, conciseness and maintainability. The performance difference likely won't kill you unless you're making a lot of arrays with lengths on the order of thousands or more.
A few other important notes. Most style guides recommend you no longer use var
without a very special reason when using ES6 or later. Use const
for variables that won't be redefined and let
for variables that will. The MDN and Airbnb's Style Guide are great places to go for more information on best practices. The questions wasn't about syntax, but it's important that people new to JS know about these new standards when searching through these reams of old and new answers.
Didn't see this method in answers, so here it is:
"0".repeat( 200 ).split("").map( parseFloat )
In result you will get zero-valued array of length 200:
[ 0, 0, 0, 0, ... 0 ]
I'm not sure about the performance of this code, but it shouldn't be an issue if you use it for relatively small arrays.
What about new Array(51).join('0').split('')
?
.map(function(a){return +a})
? –
Chancellorsville new Array(51).fill(0)
? It gives exact the same output. –
Duchess "0".repeat(100000000).split('');
significantly faster than all others. –
Cabanatuan I knew I had this proto'd somewhere :)
Array.prototype.init = function(x,n)
{
if(typeof(n)=='undefined') { n = this.length; }
while (n--) { this[n] = x; }
return this;
}
var a = (new Array(5)).init(0);
var b = [].init(0,4);
Edit: tests
In response to Joshua and others methods I ran my own benchmarking, and I'm seeing completely different results to those reported.
Here's what I tested:
//my original method
Array.prototype.init = function(x,n)
{
if(typeof(n)=='undefined') { n = this.length; }
while (n--) { this[n] = x; }
return this;
}
//now using push which I had previously thought to be slower than direct assignment
Array.prototype.init2 = function(x,n)
{
if(typeof(n)=='undefined') { n = this.length; }
while (n--) { this.push(x); }
return this;
}
//joshua's method
function newFilledArray(len, val) {
var a = [];
while(len--){
a.push(val);
}
return a;
}
//test m1 and m2 with short arrays many times 10K * 10
var a = new Date();
for(var i=0; i<10000; i++)
{
var t1 = [].init(0,10);
}
var A = new Date();
var b = new Date();
for(var i=0; i<10000; i++)
{
var t2 = [].init2(0,10);
}
var B = new Date();
//test m1 and m2 with long array created once 100K
var c = new Date();
var t3 = [].init(0,100000);
var C = new Date();
var d = new Date();
var t4 = [].init2(0,100000);
var D = new Date();
//test m3 with short array many times 10K * 10
var e = new Date();
for(var i=0; i<10000; i++)
{
var t5 = newFilledArray(10,0);
}
var E = new Date();
//test m3 with long array created once 100K
var f = new Date();
var t6 = newFilledArray(100000, 0)
var F = new Date();
Results:
IE7 deltas:
dA=156
dB=359
dC=125
dD=375
dE=468
dF=412
FF3.5 deltas:
dA=6
dB=13
dC=63
dD=8
dE=12
dF=8
So by my reckoning push is indeed slower generally but performs better with longer arrays in FF but worse in IE which just sucks in general (quel surprise).
b = []...
) is 10-15% faster than the first, but it's more than 10 times slower than Joshua's answer. –
Cryptozoic else {this.length=n;}
after the this.length
-check. This will shorten an already existing array if necessary when re-init
-ialising it to a different length n
. –
Backandforth My fastest function would be:
function newFilledArray(len, val) {
var a = [];
while(len--){
a.push(val);
}
return a;
}
var st = (new Date()).getTime();
newFilledArray(1000000, 0)
console.log((new Date()).getTime() - st); // returned 63, 65, 62 milliseconds
Using the native push and shift to add items to the array is much faster (about 10 times) than declaring the array scope and referencing each item to set it's value.
fyi: I consistently get faster times with the first loop, which is counting down, when running this in firebug (firefox extension).
var a = [];
var len = 1000000;
var st = (new Date()).getTime();
while(len){
a.push(0);
len -= 1;
}
console.log((new Date()).getTime() - st); // returned 863, 894, 875 milliseconds
st = (new Date()).getTime();
len = 1000000;
a = [];
for(var i = 0; i < len; i++){
a.push(0);
}
console.log((new Date()).getTime() - st); // returned 1155, 1179, 1163 milliseconds
I'm interested to know what T.J. Crowder makes of that ? :-)
while (len--)
.. took my processing times from about 60ms to about 54ms –
Cryptozoic This concat
version is much faster in my tests on Chrome (2013-03-21). About 200ms for 10,000,000 elements vs 675 for straight init.
function filledArray(len, value) {
if (len <= 0) return [];
var result = [value];
while (result.length < len/2) {
result = result.concat(result);
}
return result.concat(result.slice(0, len-result.length));
}
Bonus: if you want to fill your array with Strings, this is a concise way to do it (not quite as fast as concat
though):
function filledArrayString(len, value) {
return new Array(len+1).join(value).split('');
}
I was testing out the great answer by T.J. Crowder, and came up with a recursive merge based on the concat solution that outperforms any in his tests in Chrome (i didn't test other browsers).
function makeRec(len, acc) {
if (acc == null) acc = [];
if (len <= 1) return acc;
var b = makeRec(len >> 1, [0]);
b = b.concat(b);
if (len & 1) b = b.concat([0]);
return b;
},
call the method with makeRec(29)
.
It might be worth pointing out, that Array.prototype.fill
had been added as part of the ECMAScript 6 (Harmony) proposal. I would rather go with the polyfill written below, before considering other options mentioned on the thread.
if (!Array.prototype.fill) {
Array.prototype.fill = function(value) {
// Steps 1-2.
if (this == null) {
throw new TypeError('this is null or not defined');
}
var O = Object(this);
// Steps 3-5.
var len = O.length >>> 0;
// Steps 6-7.
var start = arguments[1];
var relativeStart = start >> 0;
// Step 8.
var k = relativeStart < 0 ?
Math.max(len + relativeStart, 0) :
Math.min(relativeStart, len);
// Steps 9-10.
var end = arguments[2];
var relativeEnd = end === undefined ?
len : end >> 0;
// Step 11.
var final = relativeEnd < 0 ?
Math.max(len + relativeEnd, 0) :
Math.min(relativeEnd, len);
// Step 12.
while (k < final) {
O[k] = value;
k++;
}
// Step 13.
return O;
};
}
Shortest for loop code
a=i=[];for(;i<100;)a[i++]=0;
edit:
for(a=i=[];i<100;)a[i++]=0;
or
for(a=[],i=100;i--;)a[i]=0;
Safe var version
var a=[],i=0;for(;i<100;)a[i++]=0;
edit:
for(var i=100,a=[];i--;)a[i]=0;
n
, this would be shorter: for(var a=[];n--;a[n]=0);
–
Omdurman let filled = [];
filled.length = 10;
filled.fill(0);
console.log(filled);
As of ES6 (and later versions)
You can do it like the following:
const bigNb = 1e6;
const zeros = Array(bigNb).fill(0); // array of 1M zeros
Anonymous function:
(function(n) { while(n-- && this.push(0)); return this; }).call([], 5);
// => [0, 0, 0, 0, 0]
A bit shorter with for-loop:
(function(n) { for(;n--;this.push(0)); return this; }).call([], 5);
// => [0, 0, 0, 0, 0]
Works with any Object
, just change what's inside this.push()
.
You can even save the function:
function fill(size, content) {
for(;size--;this.push(content));
return this;
}
Call it using:
var helloArray = fill.call([], 5, 'hello');
// => ['hello', 'hello', 'hello', 'hello', 'hello']
Adding elements to an already existing array:
var helloWorldArray = fill.call(helloArray, 5, 'world');
// => ['hello', 'hello', 'hello', 'hello', 'hello', 'world', 'world', 'world', 'world', 'world']
Performance: http://jsperf.com/zero-filled-array-creation/25
'0 '.repeat(200).split(' ')
–
Sensationalism What everyone else seems to be missing is setting the length of the array beforehand so that the interpreter isn't constantly changing the size of the array.
My simple one-liner would be Array.prototype.slice.apply(new Uint8Array(length))
But if I were to create a function to do it fast without some hacky workaround, I would probably write a function like this:
var filledArray = function(value, l) {
var i = 0, a = []; a.length = l;
while(i<l) a[i++] = value;
return a;
}
const item = 0
const arr = Array.from({length: 10}, () => item)
const item = 0
const arr = Array.from({length: 42}, () => item)
console.log('arr', arr)
let arr = [...Array(100).fill(0)]
In my testing by far this is the fastest in my pc
takes around 350ms for 100 million elements.
"0".repeat(100000000).split('');
for the same number of elements map(()=>0)
takes around 7000 ms and thats a humungous difference
The fastest way to do that is with forEach =)
(we keep backward compatibility for IE < 9)
var fillArray = Array.prototype.forEach
? function(arr, n) {
arr.forEach(function(_, index) { arr[index] = n; });
return arr;
}
: function(arr, n) {
var len = arr.length;
arr.length = 0;
while(len--) arr.push(n);
return arr;
};
// test
fillArray([1,2,3], 'X'); // => ['X', 'X', 'X']
forEach
only loops over elements that have been set. So fillArray(new Array(100), 'X')
won't do anything. The fallback code for IE works in either case. –
Grandeur I just use :
var arr = [10];
for (var i=0; i<=arr.length;arr[i] = i, i++);
for(var i=0, arr=[]; i<10; arr[i]=0, i++);
? –
Hypothalamus Another nice option found here http://www.2ality.com/2013/11/initializing-arrays.html
function fillArrayWithNumbers(n) {
var arr = Array.apply(null, Array(n));
return arr.map(function (x, i) { return i });
}
Recursive solutions
As noted by several others, utilizing .concat()
generally provides fast solutions. Here is a simple recursive solution:
function zeroFill(len, a){
return len <= (a || (a = [0])).length ?
a.slice(0, len) :
zeroFill(len, a.concat(a))
}
console.log(zeroFill(5));
And a general-purpose recursive array fill function:
function fill(len, v){
return len <= (v = [].concat(v, v)).length ?
v.slice(0, len) : fill(len, v)
}
console.log(fill(5, 'abc'));
You can check if index exist or not exist, in order to append +1 to it.
this way you don't need a zeros filled array.
EXAMPLE:
var current_year = new Date().getFullYear();
var ages_array = new Array();
for (var i in data) {
if(data[i]['BirthDate'] != null && data[i]['BirthDate'] != '0000-00-00'){
var birth = new Date(data[i]['BirthDate']);
var birth_year = birth.getFullYear();
var age = current_year - birth_year;
if(ages_array[age] == null){
ages_array[age] = 1;
}else{
ages_array[age] += 1;
}
}
}
console.log(ages_array);
The fastest here is
(arr = []).length = len; arr.fill(0);
new Array(2).fill(0)
will create
[ 0, 0 ]
More in the docs:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/fill
var str = "0000000...0000";
var arr = str.split("");
usage in expressions: arr[i]*1;
EDIT: if arr
supposed to be used in integer expressions, then please don't mind the char value of '0'. You just use it as follows: a = a * arr[i]
(assuming a
has integer value).
split
case everything works within one function and operates on one variable, Yes, I realize that '0' is not 0, but it's a little overhead to add 0 to match the integer type (if it's really needed). –
Silverside var a = new Array(len)
. undefined is falsey, and so a bit zero-like. (Whereas "0" is not falsey.) I had the impression the OP really wanted zeroes, though, not zero-like things. –
Ostracon I know this isn't the purpose of the question, but here's an out-of-the-box idea. Why? My CSci professor noted that there is nothing magical about 'cleansing' data with zero. So the most efficient way is to NOT do it at all! Only do it if the data needs to be zero as an initial condition (as for certain summations) -- which is usually NOT the case for most applications.
Proxy()
: new Proxy(Array(length), { get(target, prop, receiver) { const value = Reflect.get(...arguments); return value !== undefined ? value : 0; } })
–
Zepeda return Array( quantity ).fill(1).map( n => return n * Math.abs(~~(Math.random() * (1000 - 1 + 1)) + 1) );
One line.
SyntaxError: Unexpected token return
. Other than that, the gist of your solution is Array(quantity).fill(1)
, which had been posted already. The rest is a distraction. –
Fishmonger © 2022 - 2024 — McMap. All rights reserved.
let i = 0; Array.from(Array(10), ()=>i++);
– Cyanamide.fill()
and for-loop. – Homothermal