diff --git a/Data-Structures/Array/Flatten.js b/Data-Structures/Array/Flatten.js new file mode 100644 index 0000000000..709a6e576b --- /dev/null +++ b/Data-Structures/Array/Flatten.js @@ -0,0 +1,28 @@ +/** + * @function flatten + * @description Flattens a nested array into a single-level array. + * Supports both shallow (depth=1) and deep flattening. + * @param {Array} arr - The nested array to flatten + * @param {number} depth - The depth to flatten (default: Infinity) + * @returns {Array} - The flattened array + * @see https://en.wikipedia.org/wiki/Flat_array + * @example flatten([1, [2, [3, [4]]]]) => [1, 2, 3, 4] + * @example flatten([1, [2, [3]]], 1) => [1, 2, [3]] + */ +const flatten = (arr, depth = Infinity) => { + if (!Array.isArray(arr)) { + throw new TypeError('Input must be an array') + } + if (!Number.isInteger(depth) && depth !== Infinity) { + throw new TypeError('Depth must be an integer or Infinity') + } + if (depth === 0) return [...arr] + return arr.reduce((flat, item) => { + if (Array.isArray(item) && depth > 0) { + return flat.concat(flatten(item, depth - 1)) + } + return flat.concat(item) + }, []) +} + +export { flatten } diff --git a/Data-Structures/Array/test/Flatten.test.js b/Data-Structures/Array/test/Flatten.test.js new file mode 100644 index 0000000000..00f073eb25 --- /dev/null +++ b/Data-Structures/Array/test/Flatten.test.js @@ -0,0 +1,45 @@ +import { flatten } from '../Flatten.js' + +describe('flatten', () => { + test('flatten([1, 2, 3]) returns [1, 2, 3]', () => { + expect(flatten([1, 2, 3])).toEqual([1, 2, 3]) + }) + + test('flatten([1, [2, 3]]) returns [1, 2, 3]', () => { + expect(flatten([1, [2, 3]])).toEqual([1, 2, 3]) + }) + + test('flatten deeply nested array', () => { + expect(flatten([1, [2, [3, [4]]]])).toEqual([1, 2, 3, 4]) + }) + + test('flatten with depth 1', () => { + expect(flatten([1, [2, [3]]], 1)).toEqual([1, 2, [3]]) + }) + + test('flatten with depth 0 returns same array', () => { + expect(flatten([1, [2, [3]]], 0)).toEqual([1, [2, [3]]]) + }) + + test('flatten empty array returns empty array', () => { + expect(flatten([])).toEqual([]) + }) + + test('flatten with mixed types', () => { + expect(flatten([1, ['a', [true, [null]]]])).toEqual([1, 'a', true, null]) + }) + + test('flatten does not mutate original array', () => { + const arr = [1, [2, [3]]] + flatten(arr) + expect(arr).toEqual([1, [2, [3]]]) + }) + + test('throws TypeError for non-array input', () => { + expect(() => flatten('123')).toThrow(TypeError) + }) + + test('throws TypeError for invalid depth', () => { + expect(() => flatten([1, 2], 1.5)).toThrow(TypeError) + }) +})