0; i--) a[i] = a[i-1]; a[0] = "new first value"; vs a[5] = a[4]" /> 0; i--) a[i] = a[i-1]; a[0] = "new first value"; vs a[5] = a[4]" /> 0; i--) a[i] = a[i-1]; a[0] = "new first value"; vs a[5] = a[4]"/>

unshift vs assigning the values with loop vs manually assigning values by hand. Which one is faster?

100 views Asked by At

For javascript which one is faster?

a.unshift("new first value");

vs

for(i=a.length; i>0; i--) a[i] = a[i-1];
a[0] = "new first value";

vs

a[5] = a[4];
a[4] = a[3];
a[3] = a[2];
a[2] = a[1];
a[1] = a[0];
a[0] = "new first value";

Well, of course, assigning values by hand is unpractical. But there would be cases that your array has very few items that you can assign it with your hand and it's in a loop that would repeat it millions of times. So I just included it.

Then the main question is:

  1. Is there any performance difference between first two cases?
  2. And can third one be faster than both of them
3

There are 3 answers

9
Alexander Nenashev On BEST ANSWER

Seems the manual assignment is good with a small number of items only, then unshift takes the place.

` Chrome/123
-------------------------------------------------------------------------------------
>                 n=5       |       n=50        |      n=500       |      n=5000     
unshift      2.02x x10m 704 |  1.00x   x1m   96 |  1.00x   x1m 521 |  1.00x x100k 426
splice       2.03x x10m 706 |  1.38x   x1m  132 |  1.18x   x1m 614 |  1.24x x100k 529
loop         1.16x x10m 404 |  3.05x   x1m  293 |  5.34x x100k 278 |  2.63x  x10k 112
manual       1.00x x10m 348 |  1.13x  x10m 1085 |  1.52x   x1m 794 | 11.17x  x10k 476
copyWithin   6.87x  x1m 239 | 15.21x x100k  146 | 24.95x  x10k 130 | 30.75x   x1k 131
-------------------------------------------------------------------------------------
https://github.com/silentmantra/benchmark `

In Firefox splice is the fastest:

` Firefox/124
------------------------------------------------------------------------------
>                 n=5       |     n=50      |      n=500      |     n=5000    
splice       1.71x x10m 580 | 1.30x x1m 161 | 1.03x x100k 251 | 1.00x x10k 208
unshift      1.42x x10m 482 | 1.15x x1m 143 | 1.00x x100k 244 | 1.30x x10k 271
copyWithin   1.43x x10m 487 | 1.86x x1m 231 | 1.64x x100k 401 | 1.40x x10k 291
loop         1.67x x10m 568 | 3.57x x1m 443 | 2.30x x100k 562 | 2.50x x10k 521
manual       1.00x x10m 340 | 1.00x x1m 124 | 1.68x x100k 410 | 3.18x x10k 661
------------------------------------------------------------------------------
https://github.com/silentmantra/benchmark `

let $length = 5;
let b = Array.from({length:$length}, (_,i) => i+1);

// @benchmark manual
const genAssign = length => new Function('a', Array.from({length}, (_, i) => `a[${length - i}] = a[${length - i - 1}]`).join(';'))

const assign = genAssign($length);
// @run
a = b.slice();
assign(a);
a[0] = "new first value";

// @benchmark loop
a = b.slice();
for(i=a.length; i>0; i--) a[i] = a[i-1];
a[0] = "new first value";

// @benchmark unshift
a = b.slice();
a.unshift("new first value");

// @benchmark splice
a = b.slice();
a.splice(0, 0, "new first value");

// @benchmark copyWithin
a = b.slice();
a.length++;
a.copyWithin(1, 0, a.length);
a[0] = "new first value";


/*@skip*/ fetch('https://cdn.jsdelivr.net/gh/silentmantra/benchmark/loader.js').then(r => r.text().then(eval));

5
yaya jallow On

It depends but in general, directly assigning values by hand tends to be faster than using methods like unshift() or looping to assign values to an array. This is because direct assignment involves fewer operations and less overhead compared to shifting existing elements or iterating over the array.

0
trincot On

You could create a function dynamically that makes all the individual assignments, using the Function constructor.

The bigger the array, the more dramatic the difference in running time. Here is a script that creates an array with one million entries, and the dynamic function with as many assignments (+ 1). It then calls the function once and also unshift

// Test with an array with a million values
const a = [...Array(1e6).keys()];
const b = [...Array(1e6).keys()];
// Dynamically create a function that makes all assignments as individual JS statements
const f1 = new Function("a", "value", a.map((_, i) => 
    `a[${i+1}]=a[${i}];`
).reverse().join("\n") + "\na[0]=value;");
// ...and the alternative that uses the native unshift method
function f2(a, value) { a.unshift(value); }

function timeit(f, a) {
  const start = performance.now();
  f(a, "x");
  console.log(performance.now() - start);
}

timeit(f1, a);
timeit(f2, b);
// repeat with the same arrays:
a.shift(); b.shift();
timeit(f1, a);
timeit(f2, b);
// Verify the results are identical
console.log(JSON.stringify(a) === JSON.stringify(b) ? "same" : "different");

Clearly unshift wins once the array size becomes significant. This should not come as a surprise as once the JS call of unshift is made, no more JS code is concerned, and the actual shifting can rely on compiled C code.