0

I have the following function

const modules = [{courses:[...]},{courses:[...]},...]
const deleteCourses = [];
modules.forEach((mod) => {
    mod.courses.forEach((course) => {
        deleteCourses.push(course));
    }
    // versus
    deleteCourses = [...deleteCourses, ...mod.courses];
});

Assuming modules and courses to have between 30-100 length I was wondering which one of those is more efficient?

On the one hand I was taught to avoid nesting forEach loops. In the other hand array literal creates a new Array instance each time.

Thanks!

Felix Kling
  • 795,719
  • 175
  • 1,089
  • 1,143
Han Che
  • 8,239
  • 19
  • 70
  • 116
  • FWIW, the spread *element* doesn't create an array. The array literal (`[ ]`) is responsible for creating the array. – Felix Kling Nov 14 '17 at 03:28
  • Because for the question the fact that you are using spread elements probably doesn't matter much. You can as well be using `[].concat(deleteCourses, mod.courses)`. – Felix Kling Nov 14 '17 at 03:37

1 Answers1

3

It would seem that nested forEach is very much faster, as this jsPerf shows:

Setup:

const modules = Array(30).fill({courses:Array(30).fill(1)}) //30x30 elements
let deleteCourses = [];

Case 1: nested forEach - 29,293 ops/sec

modules.forEach((mod) => {
    mod.courses.forEach((course) => {
        deleteCourses.push(course);
    })
})

Case 2: ES6 Spread Operator - 49.13 ops/sec

modules.forEach((mod) => {
    deleteCourses = [...deleteCourses, ...mod.courses];
})

That's about 600x faster for that 30x30 sample

This makes sense when you consider the amount of redundancy in respreading deleteCourses on every iteration. In contrast to nested forEach, the number of addition operations performed per iteration is about the length of deleteCourses for that iteration. That number is also growing on every iteration.

So the difference in performance has little to do with the creation of new Array instances, and much to do with the multitude of redundant steps created by this misusage of the spread operator.

To be sure, looking at the two cases individually, we can see that:

  • the ES6 Spread Operator algorithm is exponential: O(2^n)
  • the nested forEach algorithm is linear: O(n)
b3nThomas
  • 47
  • 6
strider
  • 5,674
  • 4
  • 24
  • 29