Skip to content

Instantly share code, notes, and snippets.

@evanplaice
Last active November 6, 2019 05:01
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save evanplaice/dd0a727ff0cc1397f33e3c00bec05d91 to your computer and use it in GitHub Desktop.
Save evanplaice/dd0a727ff0cc1397f33e3c00bec05d91 to your computer and use it in GitHub Desktop.
A collection of Array.flat() implementations in Javascript
/* eslint no-labels: 0 */
/**
* Flattens an array of nested arrays using iteration w/ O(n) time complexity
*
* @param {Array} array input array
* @returns {Array} the flattened array
*
* @example
* const result = flatIterative([1, [2, [3, [4]]]]);
* console.log(result);
* > [1, 2, 3, 4]
*/
function flatIterative (array) {
let start = 0;
const stack = [];
const idx = [];
const output = [];
outer: do {
inner: for (let i = start; i < array.length; i++) {
// handle arrays
if (Array.isArray(array[i])) {
// Edge Case: skip empty arrays
if (array[i].length === 0) { continue inner; }
stack.push([array, i]); // outer array goes on the stack
idx.push(i + 1); // mark next index of outer array
start = 0; // reset the start index
array = array[i]; // inner array gets traversed next
continue outer; // restart the array traversal
}
// handle values
output.push(array[i]);
}
// pop the stack if the top layer is done
array = stack.pop();
start = idx.pop();
} while (stack.length > 0);
return output;
}
module.exports = flatIterative;
const test = require('tape');
const flat = require('./flat-iterative.js');
test('flat(array) - should return an empty array if the input is empty', t => {
const expect = [];
const result = flat([]);
t.equal(Object.prototype.toString.call(result), '[object Array]', 'return type');
t.equal(result.length, 0, 'output length');
t.deepEqual(result, expect, 'output value');
t.end();
});
test('flat(array) - an already flat array should return the same as the input', t => {
const expect = [1, 2, 3, 4, 5];
const result = flat([1, 2, 3, 4, 5]);
t.equal(Object.prototype.toString.call(result), '[object Array]', 'return type');
t.equal(result.length, 5, 'output length');
t.deepEqual(result, expect, 'output value');
t.end();
});
test('flat(array) - should flat multiple levels of nested arrays with ascending depth', t => {
const expect = [1, 2, 3, 4];
const result = flat([1, [2, [3, [4]]]]);
t.equal(Object.prototype.toString.call(result), '[object Array]', 'return type');
t.equal(result.length, 4, 'output length');
t.deepEqual(result, expect, 'output value');
t.end();
});
test('flat(array) - should flatten if the input includes empty arrays', t => {
const expect = [1, 3];
const result = flat([1, [], 3, []]);
t.equal(Object.prototype.toString.call(result), '[object Array]', 'return type');
t.equal(result.length, 2, 'output length');
t.deepEqual(result, expect, 'output value');
t.end();
});
/**
* Flattens an array of nested arrays using recursion
*
* @param {Array} array input array
* @returns {Array} the flattened array
*
* @example
* const result = flatRecursive([1, [2, [3, [4]]]]);
* console.log(result);
* > [1, 2, 3, 4]
*/
function flatRecursive (array, output = []) {
array.forEach((item) => {
if (Array.isArray(item)) {
flatRecursive(item, output);
} else {
output.push(item);
}
});
return output;
}
module.exports = flatRecursive;
const test = require('tape');
const flat = require('./flat-recursive.js');
test('flat(array) - should return an empty array if the input is empty', t => {
const expect = [];
const result = flat([]);
t.equal(Object.prototype.toString.call(result), '[object Array]', 'return type');
t.equal(result.length, 0, 'output length');
t.deepEqual(result, expect, 'output value');
t.end();
});
test('flat(array) - an already flat array should return the same as the input', t => {
const expect = [1, 2, 3, 4, 5];
const result = flat([1, 2, 3, 4, 5]);
t.equal(Object.prototype.toString.call(result), '[object Array]', 'return type');
t.equal(result.length, 5, 'output length');
t.deepEqual(result, expect, 'output value');
t.end();
});
test('flat(array) - should flat multiple levels of nested arrays with ascending depth', t => {
const expect = [1, 2, 3, 4];
const result = flat([1, [2, [3, [4]]]]);
t.equal(Object.prototype.toString.call(result), '[object Array]', 'return type');
t.equal(result.length, 4, 'output length');
t.deepEqual(result, expect, 'output value');
t.end();
});
test('flat(array) - should flatten if the input includes empty arrays', t => {
const expect = [1, 3];
const result = flat([[[1], [], 3], []]);
t.equal(Object.prototype.toString.call(result), '[object Array]', 'return type');
t.equal(result.length, 2, 'output length');
t.deepEqual(result, expect, 'output value');
t.end();
});
/**
* Flattens an array of nested arrays
*
* @param {Array} array input array
* @param {Array} initial reducer initial state
* @returns {Array} the flattened array
*
* @example
* const result = flatReduce([1, [2, [3, [4]]]]);
* console.log(result);
* > [1, 2, 3, 4]
*/
function flatReduce (array, initial = []) {
return array.reduce((acc, curr) => {
if (Array.isArray(curr)) {
acc = flatReduce(curr, acc);
} else {
acc.push(curr);
}
return acc;
}, initial);
}
module.exports = flatReduce;
const test = require('tape');
const flat = require('./flat-reduce.js');
test('flat(array) - should return an empty array if the input is empty', t => {
const expect = [];
const result = flat([]);
t.equal(Object.prototype.toString.call(result), '[object Array]', 'return type');
t.equal(result.length, 0, 'output length');
t.deepEqual(result, expect, 'output value');
t.end();
});
test('flat(array) - an already flat array should return the same as the input', t => {
const expect = [1, 2, 3, 4, 5];
const result = flat([1, 2, 3, 4, 5]);
t.equal(Object.prototype.toString.call(result), '[object Array]', 'return type');
t.equal(result.length, 5, 'output length');
t.deepEqual(result, expect, 'output value');
t.end();
});
test('flat(array) - should flat multiple levels of nested arrays into one array', t => {
const expect = [1, 2, 3, 4];
const result = flat([1, [2, [3, [4]]]]);
t.equal(Object.prototype.toString.call(result), '[object Array]', 'return type');
t.equal(result.length, 4, 'output length');
t.deepEqual(result, expect, 'output value');
t.end();
});
@evanplaice
Copy link
Author

evanplaice commented Nov 6, 2019

The full prod-ready project repository is available @ https://github.com/evanplaice/flat-demo

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment