What is Flattening in JavaScript?
Flattening refers to the process of converting a complex structure, such as a deeply nested array or object, into a simpler, single-level structure. It is one of the frequently asked questions in interviews.
Real-Life Meaning of Flattening
Imagine you have a stack of papers organized in multiple folders inside a cabinet. If you want to access all the papers quickly, you take them out and arrange them in a single pile. This is similar to flattening in programming—taking nested structures and converting them into a linear format for easy access and manipulation.
Array Flattening in JavaScript
In JavaScript, flattening an array means converting an array that contains nested arrays into a single-level array. This is useful when working with deeply nested data structures, such as API responses or hierarchical datasets.
Ways to Flatten a Nested Array
Using Recursion
Recursion is a common approach where we iterate through the array and push elements to a new array.
function flattenArray(arr) {
let result = [];
arr.forEach(item => {
if (Array.isArray(item)) {
result.push(...flattenArray(item));
} else {
result.push(item);
}
});
return result;
}
// Example Usage
const nestedArr = [1, [2, [3, 4], 5], 6];
console.log(flattenArray(nestedArr));
// Output: [1, 2, 3, 4, 5, 6]
Works well for moderate levels of nesting.
Issue: If the array is deeply nested (e.g., thousands of levels), it may cause a stack overflow error.
Best for: Small to moderately nested arrays.
flat() method (ES6)The flat() method is the simplest way to flatten an array in modern JavaScript.
const nestedArr = [1, [2, [3, 4], 5], 6];
const flattened = nestedArr.flat(Infinity);
console.log(flattened);
// Output: [1, 2, 3, 4, 5, 6]
Best method for modern JavaScript.
Uses built-in optimizations and handles deep nesting efficiently.
Best for: Any level of nesting (if using modern JavaScript).
reduce()The reduce() method can be used to iterate through the array and merge nested arrays.
function flattenArrayReduce(arr) {
return arr.reduce((acc, val) =>
Array.isArray(val) ? acc.concat(flattenArrayReduce(val)) : acc.concat(val),
[]);
}
// Example Usage
const nestedArr = [1, [2, [3, 4], 5], 6];
console.log(flattenArrayReduce(nestedArr));
// Output: [1, 2, 3, 4, 5, 6]
Works well, but since it relies on recursion, deeply nested structures may cause stack overflow.
Best for: Small to moderately nested arrays.
Instead of recursion, we can use a stack to iteratively process elements.
function flattenArrayStack(arr) {
let stack = [...arr];
let result = [];
while (stack.length) {
let next = stack.pop();
if (Array.isArray(next)) {
stack.push(...next);
} else {
result.unshift(next);
}
}
return result;
}
// Example Usage
const nestedArr = [1, [2, [3, 4], 5], 6];
console.log(flattenArrayStack(nestedArr));
// Output: [1, 2, 3, 4, 5, 6]
Uses an iterative approach instead of recursion, making it safe from stack overflow.
Best for: Extremely deep nesting.
Object Flattening in JavaScript
Object flattening involves converting a deeply nested object into a key-value pair structure with dot notation or a similar approach. This is particularly helpful when working with configurations, form data, or JSON responses that need to be processed in a flattened format.
Ways to Flatten a Nested Object
Using Recursion
Recursion is a common approach to flatten a deeply nested object. It iterates through each key and adds it to a new object with a dot-separated path.
function flattenObject(obj, parentKey = "", result = {}) {
for (let key in obj) {
let newKey = parentKey ? parentKey + "." + key : key;
if (typeof obj[key] === "object" && obj[key] !== null) {
flattenObject(obj[key], newKey, result);
} else {
result[newKey] = obj[key];
}
}
return result;
}
// Example Usage
const nestedObj = {
user: {
name: "Prakash",
address: { city: "New Delhi", zip: "10001" }
}
};
console.log(flattenObject(nestedObj));
// Output: { "user.name": "Prakash", "user.address.city": "New Delhi", "user.address.zip": "10001" }
Works well for moderate levels of nesting.
Issue: If the object is deeply nested (e.g., thousands of levels), it may cause a stack overflow error.
Best for: Small to moderately nested objects.
Instead of recursion, we can use a stack to iteratively process each key-value pair.
function flattenObjectIterative(obj) {
let stack = [{ obj, prefix: "" }];
let result = {};
while (stack.length) {
let { obj, prefix } = stack.pop();
for (let key in obj) {
let newKey = prefix ? prefix + "." + key : key;
if (typeof obj[key] === "object" && obj[key] !== null) {
stack.push({ obj: obj[key], prefix: newKey });
} else {
result[newKey] = obj[key];
}
}
}
return result;
}
// Example Usage
const nestedObj = {
user: {
name: "Prakash",
address: { city: "New Delhi", zip: "10001" }
}
};
console.log(flattenObjectIterative(nestedObj));
// Output: { "user.name": "Prakash", "user.address.city": "New Delhi", "user.address.zip": "10001" }
Uses an iterative approach instead of recursion, making it safe from stack overflow.
Best for: Extremely deep nesting.
Key Takeaways
- Flattening converts nested structures (arrays or objects) into a single-level structure.
- Arrays can be flattened using recursion,
flat(Infinity),reduce(), or an iterative stack-based approach. - Objects require a recursive approach or iterative techniques to flatten key-value pairs into a single-level object.
- Deeply nested structures may cause performance issues or stack overflow errors if not handled properly.
flat(Infinity)is the easiest method for arrays but is limited to arrays only.- Stack-based iteration is the best choice for extremely deep structures as it avoids recursion limits.
- Flattening helps in working with deeply nested API responses, database structures, and hierarchical data efficiently.