Flatten an array – loop or reduce?

Posted on

Problem

Problem: Concat all sub-arrays of a given array.

Example input: [[0, 1], [2, 3], [4, 5]]

Example output: [0, 1, 2, 3, 4, 5]

Solution A: Use a loop

var flattened=[];
for (var i=0; i<input.length; ++i) {
    var current = input[i];
    for (var j=0; j<current.length; ++j)
        flattened.push(current[j]);
}

Solution B: Use reduce

var flattened = input.reduce(function(a, b) {
    return a.concat(b);
}, []);

Solution B looks much shorter and easier to understand, but, it seems to be much more resource-wasteful – for each element of the input, a new array is created – the concatenation of a and b. On the contrary, solution A uses a single array ‘flattened’, which is updated during the loop.

So, my question is: which solution is better? Is there a solution that combines the best of both worlds?

Solution

Here is the performance test for these two and couple more approaches (one suggested by @elclanrs in the comments).

The performance differences will vary significantly across different browsers, and even different version on same browser, as browser these days try to optimize javascript very aggressively.

Unless you are dealing with very large arrays or this operation is performed repeatedly in quick succession, I would suggest you to use simplest and clearest approach. But, that being said the loop solution is also not that complex or big anyway (and it performs better than others especially on firefox)

Taking @elclanrs solution in the comments above and modifying slightly to overcome the limitations with ultra long arrays and argument expansion, you could use something like this:

function flattenLongArray(input) {
    var LIMIT = 32768;
    var end, result = [];


    for(var i = 0; i < input.length; i+=LIMIT) {
        end = Math.min(i+LIMIT, input.length) - 1;
        Array.prototype.concat.apply(result, input.slice(i, end));
    }

    return result;
}

This is admittedly verbose, but it works.

Leave a Reply

Your email address will not be published. Required fields are marked *