Skip to content

Commit

Permalink
Avoid array creation in recursive flatten
Browse files Browse the repository at this point in the history
fixes jashkenas#2202

If you have a n=1000 deeply nested array with k=1000 elements in the leaf node then it would be copied n times leading to O(n*k). After this fix, it will take O(n+k)
  • Loading branch information
erikbern authored and megawac committed Jun 1, 2015
1 parent c9a9f15 commit 427fa96
Show file tree
Hide file tree
Showing 2 changed files with 14 additions and 7 deletions.
5 changes: 5 additions & 0 deletions test/arrays.js
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,11 @@
equal(_.flatten([_.range(10), _.range(10), 5, 1, 3]).length, 23);
equal(_.flatten([new Array(1000000), _.range(56000), 5, 1, 3]).length, 1056003, 'Flatten can handle massive collections');
equal(_.flatten([new Array(1000000), _.range(56000), 5, 1, 3], true).length, 1056003, 'Flatten can handle massive collections');

var x = _.range(100000);
for (var i = 0; i < 1000; i++) x = [x];
deepEqual(_.flatten(x), _.range(100000), 'Flatten can handle very deep arrays');
deepEqual(_.flatten(x, true), x[0], 'Flatten can handle very deep arrays with shallow');
});

test('without', function() {
Expand Down
16 changes: 9 additions & 7 deletions underscore.js
Original file line number Diff line number Diff line change
Expand Up @@ -490,17 +490,19 @@
};

// Internal implementation of a recursive `flatten` function.
var flatten = function(input, shallow, strict) {
var output = [], idx = 0;
var flatten = function(input, shallow, strict, output) {
output = output || [];
var idx = output.length;
for (var i = 0, length = getLength(input); i < length; i++) {
var value = input[i];
if (isArrayLike(value) && (_.isArray(value) || _.isArguments(value))) {
//flatten current level of array or arguments object
if (!shallow) value = flatten(value, shallow, strict);
var j = 0, len = value.length;
output.length += len;
while (j < len) {
output[idx++] = value[j++];
if (shallow) {
var j = 0, len = value.length;
while (j < len) output[idx++] = value[j++];
} else {
flatten(value, shallow, strict, output);
idx = output.length;
}
} else if (!strict) {
output[idx++] = value;
Expand Down

0 comments on commit 427fa96

Please sign in to comment.