Flatten the Object - JavaScript
Tags: javascript, programming, recursion, tutorial
Published: 2022-05-11 01:00:14

Hello, Hope you're doing well & solving interesting problems using your programming skills.🔥

In this blog, we will try to solve one such interesting problem related to **flattening the object** which is asked in javascript interviews.  

I have breakdown the whole tutorial into 4 sections -

1. Input
2. Output
3. Approach (logic)
4. Assemble (put everything together)

Let's start!🚀

## Input
This is our unflatten object containing data of an user.  
```javascript
const user = {
  name: 'John',
  address: {
    personal: {
      street: 'Victor Plains',
      city: 'Wisokyburgh',
    },
    office: {
      city: 'South Elvis',
      area: {
        landmark: 'Hoeger Mall',
      },
    },
  },
};
```
## Output
We need to flat the object like this - 
```javascript
{
  user_name: "John",
  user_address_personal_street: "Victor Plains",
  user_address_personal_city: "Wisokyburgh",
  user_address_office_city: "South Elvis",
  user_address_office_area_landmark: "Hoeger Mall"
}
```
## Approach
If you closely look at our input object, you'll see a pattern of nested objects. 
```javascript
const OBJECT = {
  name: 'John',
  OBJECT: {
    OBJECT: {
      street: 'Victor Plains',
      city: 'Wisokyburgh',
    },
    OBJECT: {
      city: 'South Elvis',
      OBJECT: {
        landmark: 'Hoeger Mall',
      },
    },
  },
};
```
So we need to iterate over the nested objects & flat them one by one.
But if we want to flat each object at a time, we need to breakdown the nested objects into a single object recursively.

**Recursively?** 🤔

Yes, We will use recursion to solve this problem. 

## What is Recursion?

Recursion is a phenomenon used to solve complex problems by breaking them down into simpler ones.

## Recursive Function

When we apply this phenomenon in a function, that function will call itself again and again until we reach at the breaking condition.

**Let's define our recursive function  - **

```javascript
const recursiveFunc = (obj, parentKey, flattenObj) => { 
  // we will write our logic here.
};
```

- obj: our input object
- parentKey: To keep a track of parent object because we need to append parent keys while iterating over the input obj - `user_address_office_area_landmark: "Hoeger Mall"`
- flattenObj: an empty object to store flatten obj on each iteration.

While looping through unflatten object, we will only flat those key whose type is object.

So, we need a function which takes `key` as item & return `true` if the key is an object.

```javascript
const isAnObject = (item) => {
    return (
      item !== null &&
      typeof item === 'object' &&
      Object.prototype.toString.call(item) === '[object Object]'
    );
  };
```

Now we need to loop through the input object ( unflatten ) & store the flatten key-value pair inside `flattenObj` 

```javascript
for (let key in obj) { // 1
    let finalKey = `${parentKey}_${key}`; // 2
    if (isAnObject(obj[key])) { // 3
      recursiveFunc(obj[key], finalKey, flattenObj); // 4
    } else {
      flattenObj[finalKey] = obj[key]; // 5
    }
  }
```
Let's understand it line by line.

// 1 - `let key in obj` this line will give key of the key-value pair on each iteration. `name`, `address`, `personal` & so on. 

// 2 - we are adding the parent key before current key to make it look like this at the end - `user_address_personal_street: "Victor Plains"`. When we iterate over address obj, the user will be the parent. so we add the user before address - `user_address` & store it in `finalKey`.

// 3 - we are checking if the current key is an object or not using `isAnObject` function which we've already defined.

// 4 - If the key is an object, we will call `recursiveFunc` again with the updated value of `obj`, `parentKey` & `flattenObj`. 

// 5 - If the key is not object, we will store the `finalKey` (user_address_personal_street) as key & `key`("Victor Plains") as value inside flattenObj.

Let's pass our initial data & console the output.
```javascript
let flattenObj = {};
recursiveFunc(user, 'user', flattenObj);
console.log(flattenObj);
```

So when we invoke the recursiveFunc, it'll run the loop & iterate over `user` object. 
Initial value -
1. obj: user
2. parentKey: 'user'
3. flattenObj: {}

## First Iteration

Now `key` is `name`
- finalKey = 'user_name'
- `name` is not an object
**Result**

```javascript
flattenObj = { user_name: "John" }
```

## Second Iteration

Now `key` is `address`
- finalKey = 'user_address'
- `address` is an object

**Result**
call recursiveFunc again with new values -  

- obj: address
- parentKey: "user_address"
- `flattenObj: { user_name: "John" }`

## Third Iteration

Now `key` is `personal`
- finalKey = 'user_address_personal'
- `personal` is an object

**Result**
call recursiveFunc again with new values -  

- obj: personal
- parentKey: "user_address_personal"
- `flattenObj: { user_name: "John" }`

## Fourth Iteration

Now `key` is `street`
- finalKey = 'user_address_personal_street'
- `street` is not an object

**Result**
```javascript
flattenObj = { 
  user_name: "John",
  user_address_personal_street: "Victor Plains"
}
```

...and iterations will go on until it reach the last key.
**The final output will be - 🎉**

```javascript
flattenObj = {
  user_name: "John",
  user_address_personal_street: "Victor Plains",
  user_address_personal_city: "Wisokyburgh",
  user_address_office_city: "South Elvis",
  user_address_office_area_landmark: "Hoeger Mall"
}
```

## Assemble
Here's the whole code for flattening an object.

```javascript
const user = {
  name: 'John',
  address: {
    personal: {
      street: 'Victor Plains',
      city: 'Wisokyburgh',
    },
    office: {
      city: 'South Elvis',
      area: {
        landmark: 'Hoeger Mall',
      },
    },
  },
};

const recursiveFunc = (obj, parentKey, flattenObj) => { 
  const isAnObject = (item) => { 
    return (
      item !== null &&
      typeof item === 'object' &&
      Object.prototype.toString.call(item) === '[object Object]'
    );
  };

  for (let key in obj) { 
    let finalKey = `${parentKey}_${key}`; 
    if (isAnObject(obj[key])) {
      recursiveFunc(obj[key], finalKey, flattenObj); 
    } else {
      flattenObj[finalKey] = obj[key]; 
    }
  }
};

let flattenObj = {};
recursiveFunc(user, 'user', flattenObj);
console.log(flattenObj);

```

## Conclusion
Hope after reading this blog, you've understood - 
1. How to approach a problem.  
2. How to flatten an object using recursion.

If you find this blog as helpful, don't forget to share it.
And incase you know any other ways to flatten an object in javaScript, please share it in the comments.

Thank you 🙂
Connect with me on - [Twitter](https://twitter.com/helloAbhishekk)  [Instagram](https://instagram.com/abhishekgautam.ig)