Given an nested object which can have any type of object, deep flatten it and return the new object in Javascript.
For example
Input: { A: "12", B: 23, C: { P: 23, O: { L: 56 }, Q: [1, 2] } } Output: { "A": "12" "B": 23, "C.O.L": 56, "C.P": 23, "C.Q.0": 1, "C.Q.1": 2, }
Deep flatten object Javascript
In the output if you notice, when we have nested objects the key is concatenated till there is a non-object value, similar for the array, the key is concatenated on the index.
Given the way we want the output, there are two ways in which we can solve this problem, one is using stack and other is using recursion.
In this case we will go with recursion as I find it simpler to handle recursive functions.
There are three different cases which we need to handle.
- Check if the value of the given key is object or not.
- If it is not an object then add that value to the output.
- Else, check if the value is array or not.
- If it is object then recursively call the same function with value and pass the key to be used as prefix and return the output in existing result.
- Otherwise, iterate the value and use the array’s index along with existing key as a new key and then store it in the output.
- Alternatively, we can convert the array to object and then recursively call the same function as we did in step 4.
We are going to see the both approaches along with two different ways to check the type of value.
Approach 1.
const flatten = (obj, prefix) => { //store the result let output = {}; //iterate the object for(let k in obj){ let val = obj[k]; //get the type const type = Object.prototype.toString.call(val); //object if(type === "[object Object]"){ //new key const newKey = prefix ? prefix + "." + k : k; const newObj = flatten(val, newKey); output = {...output, ...newObj}; } //array else if(type === "[object Array]"){ //iterate array for(let i = 0; i < val.length; i++){ //new key const newKey = prefix ? prefix + "." + k + "." + i : k + "." + i; output = {...output, [newKey]: val[i]}; } } // normal value else{ //new key const newKey = prefix ? prefix + "." + k : k; output = {...output, [newKey]: val}; } } return output; }
Input: const nested = { A: "12", B: 23, C: { P: 23, O: { L: 56 }, Q: [1, 2] } }; console.log(flatten(nested)); Output: { "A": "12" "B": 23, "C.O.L": 56, "C.P": 23, "C.Q.0": 1, "C.Q.1": 2, }
Approach 2.
The problem in the first approach is we have to create the new key in each condition which is not a good and it is because we are iterating the array in between, if we could convert that array to object then we can get rid of this problem.
Also we can use ES6 features to differentiate between object and array.
const flatten = (obj, prefix) => { //store the result let output = {}; //iterate the object for(let k in obj){ let val = obj[k]; //new key const newKey = prefix ? prefix + "." + k : k; //array and object both are object in js if(typeof val === "object"){ // if it is array if(Array.isArray(val)){ //use rest & spread together to convert //array to object const { ...arrToObj } = val; const newObj = flatten(arrToObj, newKey); output = {...output, ...newObj}; } //if it is object else{ const newObj = flatten(val, newKey); output = {...output, ...newObj}; } } // normal value else{ output = {...output, [newKey]: val}; } } return output; }
Input: const nested = { A: "12", B: 23, C: { P: 23, O: { L: 56 }, Q: [1, 2] } }; console.log(flatten(nested)); Output: { "A": "12" "B": 23, "C.O.L": 56, "C.P": 23, "C.Q.0": 1, "C.Q.1": 2, }