Last active
January 8, 2018 22:32
-
-
Save anri-asaturov/c749c3dba70aee77ad52b0d7d3e66ce6 to your computer and use it in GitHub Desktop.
Flatten array
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ------------- MODULE ------------------- | |
/** | |
* Flattens array containing nested arrays into a one-level array. | |
* @param {Array} arr - array to flatten | |
* @returns {Array} flat array, always a new instance | |
*/ | |
function flattenArray(arr) { | |
if (!Array.isArray(arr)) throw new Error('First argument should be Array.'); | |
// result accumulator | |
const ret = []; | |
// starts recursive call chain | |
iterate(ret, arr); | |
return ret; | |
} | |
/** | |
* Helper function to process one array and make recursive calls for nested arrays. | |
* @param {Array} accumulator - result accumulator | |
* @param {Array} arrLevel - one array level to process | |
*/ | |
function iterate(accumulator, arrLevel) { | |
// not verifying arguments since it's an internal module function | |
arrLevel.forEach(item => { | |
if (Array.isArray(item)) { | |
// process nested array | |
iterate(accumulator, item); | |
} else { | |
accumulator.push(item); | |
} | |
}); | |
} | |
// module.exports = { flattenArray }; | |
// -------------- TESTING ------------------------------------------- | |
// I do know and use several test frameworks and assertion libraries | |
// in my everyday work (recently mocha, chai and cucumberjs) | |
// but I assumed you will want to paste this gist to console | |
// and see if it works, so, here's a vanilla test runner :D | |
/** | |
* Test helper, performs shallow comparison of 2 arrays | |
* @param {Array} arr1 | |
* @param {Array} arr2 | |
* @returns {bool} true - if length and elements of one array are strictly equal to elements of the other | |
*/ | |
function shallowCompareArrays(arr1, arr2) { | |
if (!Array.isArray(arr1) | |
|| !Array.isArray(arr2) | |
|| arr1.length !== arr2.length) return false; | |
for (let i = 0; i < arr1.length; i++) { | |
if (arr1[i] !== arr2[i]) return false; | |
} | |
return true; | |
} | |
/** | |
* @callback testCaseCode | |
* @returns {Array} actual value | |
*/ | |
/** | |
* Test helper to execute one test case. | |
* @param {string} name - test case name | |
* @param {testCaseCode} testFn - test case code | |
* @param {Array} expected - expected result, | |
* @param {bool} [shouldThrow=false] - pass 'true' if test case is expected to throw | |
*/ | |
function runTestCase(name, testFn, expected, shouldThrow = false) { | |
console.log(`Test case: ${name}...`); | |
let result = true; | |
try { | |
const actual = testFn(); | |
result = shallowCompareArrays(actual, expected); | |
console.assert( | |
result, | |
'Expected result did not match actual', | |
'expected:', expected, | |
'actual:', actual | |
); | |
} catch (err) { | |
if (!shouldThrow) { | |
console.error(err); | |
return; | |
} | |
} | |
if (result) console.log('...success!'); | |
} | |
// [ | |
// case name : string, | |
// case code : function, | |
// expected result : array, | |
// should throw : [bool] | |
// ] | |
const testCases = [ | |
[ | |
'undefined argument', | |
() => flattenArray(), | |
null, | |
true | |
], [ | |
'null argument', | |
() => flattenArray(null), | |
null, | |
true | |
], [ | |
'Number argument', | |
() => flattenArray(42), | |
null, | |
true | |
], [ | |
'String argument', | |
() => flattenArray('[1,2,3]'), | |
null, | |
true | |
], [ | |
'Empty array', | |
() => flattenArray([]), | |
[] | |
], [ | |
'Single element', | |
() => flattenArray([[[1]]]), | |
[1] | |
], [ | |
'Flat array', | |
() => flattenArray([1, 2, 3, 4, 5]), | |
[1, 2, 3, 4, 5] | |
], [ | |
'2 levels - array start', | |
() => flattenArray([[1, 2, 3, 4], 5]), | |
[1, 2, 3, 4, 5] | |
], [ | |
'2 levels - array middle', | |
() => flattenArray([1, [2, 3], 4, 5]), | |
[1, 2, 3, 4, 5] | |
], [ | |
'2 levels - array end', | |
() => flattenArray([1, 2, 3, [4, 5]]), | |
[1, 2, 3, 4, 5] | |
], [ | |
'2 levels - full array', | |
() => flattenArray([[1, 2, 3, 4, 5]]), | |
[1, 2, 3, 4, 5] | |
], [ | |
'3 levels', | |
() => flattenArray([[1, [2]], 3, [4, 5]]), | |
[1, 2, 3, 4, 5] | |
] | |
]; | |
function vanillaTestRunner() { | |
testCases.forEach(testCase => runTestCase(...testCase)); | |
} | |
//------ | |
vanillaTestRunner(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment