Filter nested object in Javascript

Create a function in javascript which will take a nested object and a filter function as input and return the filtered object.

Example

Input:
const obj = {
  a: 1,
  b: {
    c: "Hello World",
    d: 2,
    e: {
     f: {
       g: -4,
      },
    },
    h: "Good Night Moon",
  },
};

const filter = (s) => typeof s === "string";

Output:
{
  b: {
    c: "Hello World",
    h: "Good Night Moon",
  }
};

The only clause to this function is that filtering should happen in-place, which means we cannot create a copy of this object and then perform operation on it.

We can filter the object by removing the entries in object which fails the filter condition. Basically we have to handle the following cases.

  • Iterate all the entries of the object and in each iteration check.
  • If the value of the current key is an object then recur and call the same function with the current value.
  • Else, if the value is empty object or fails the filter condition then delete the current object.

To check if the value is empty object or not, we will convert the value to string using JSON.stringify() method and then compare it.

const deepFilter = (obj, filter) => {
  //iterate the object
  for (let key in obj) {
    const val = obj[key];

    //if val is also object (nested)
    if (typeof val === "object") {
      //recur
      deepFilter(val, filter);
    } 
    // normal value
    else {
      //current val fails filter condition
      //delete it
      if (filter(val) === false) {
        delete obj[key];
      }
    }

    //if value is empty obj
    //delete it
    if (JSON.stringify(val) === "{}") {
      delete obj[key];
    }
  }
};
Input:
const obj = {
  a: 1,
  b: {
    c: "Hello World",
    d: 2,
    e: {
     f: {
       g: -4,
      },
    },
    h: "Good Night Moon",
  },
};

//filter's in-place
deepFilter(obj, (s) => typeof s === "string");

console.log(obj);

Output:
{
  b: {
    c: "Hello World",
    h: "Good Night Moon",
  }
};