Typescript - filter all matching objects in the object and its exactly the same children


One common task in software development is filtering objects based on specific criteria. In this tutorial, we will explore how to filter all matching objects in an object and its exactly the same children using Typescript. This technique can be particularly useful when working with complex data structures or when extracting specific information from nested objects.

We will utilize TypeScript's powerful features, such as type annotations and object manipulation, to achieve this.

Recursive Function with Type Guards for Filtering Matching Objects and Their Children

We can use a recursive approach to filter all matching objects in an object and it is exactly the same children. The algorithm will iterate over the properties of the object and its children, checking if they match the filter value. The corresponding property or object will be included in the filtered result if a match is found.

Here is an outline of the steps involved −

  • Create a new empty object to store the filtered result.

  • Iterate over the properties of the input object.

  • For each property, check if it matches the filter value.

  • If the property is an object, recursively call the filterMatchingObjects function on it.

  • If the property is a match or contains matching children, add it to the filtered result object.

  • Return the filtered result object.

Here's an example −

function filterMatchingObjects(obj: any, filterValue: any): any {
   const filteredObj: any = {};
   for (const key in obj) {
      if (obj.hasOwnProperty(key)) {
         const value = obj[key];
         if (typeof value === "object" && value !== null) {
            lterMatchingObjects(value, filterValue);
         } else if (value === filterValue) {
            filteredObj[key] = value;
         }
      }
   }
   return Object.keys(filteredObj).length &g; 0 ? filteredObj : null;
}

Example 1

In this example, we defined an interface Product that represents the structure of each product object. We then created an array of Product objects called products.

After defining the data, we utilized the filter() method on the product array. This method takes a callback function that checks if each product's category property matches the filter condition, in this case, "electronics". It creates a new array called filteredProducts that only contains the products with the category "electronics".

Users can observe in the output that the filteredProducts array consists of three products: "Macbook Pro", "AirPods Pro", and "Kindle Paperwhite". These are the products that satisfy the filter condition.Users can observe in the output that the filteredProducts array consists of three products: "Macbook Pro", "AirPods Pro", and "Kindle Paperwhite". These are the products that satisfy the filter condition.

interface Product {
   name: string;
   category: string;
   price: number;
}

const products: Product[] = [
   { name: "Macbook Pro", category: "electronics", price: 2000 },
   { name: "AirPods Pro", category: "electronics", price: 249 },
   { name: "Leather Jacket", category: "clothing", price: 350 },
   { name: "Running Shoes", category: "footwear", price: 120 },
   { name: "Kindle Paperwhite", category: "electronics", price: 119 },
];

const filteredProducts = products.filter((product) =&g; product.category === "electronics");
console.log(filteredProducts)

On compiling, it will generate the following JavaScript code −

var products = [
   { name: "Macbook Pro", category: "electronics", price: 2000 },
   { name: "AirPods Pro", category: "electronics", price: 249 },
   { name: "Leather Jacket", category: "clothing", price: 350 },
   { name: "Running Shoes", category: "footwear", price: 120 },
   { name: "Kindle Paperwhite", category: "electronics", price: 119 },
];
var filteredProducts = products.filter(function (product) { return product.category === "electronics"; });
console.log(filteredProducts);

Output

The above code will produce the following output −

[
  { name: 'Macbook Pro', category: 'electronics', price: 2000 },
  { name: 'AirPods Pro', category: 'electronics', price: 249 },
  { name: 'Kindle Paperwhite', category: 'electronics', price: 119 }
]

Example 2

In this example, we define an interface User that represents the structure of each user object, including their preferences. We create an array of User objects called users. Then, to filter the users based on their dark mode preference, we define the filterMatchingObjects function. This function takes an array of User objects and a filterValue (a boolean representing the dark mode preference) as parameters.

Within the function, we iterate over each User object and check if the darkMode property of their preferences matches the filterValue. If a match is found, the user is added to the filteredUsers array.

In the output, users can observe that the usersWithDarkMode array contains only the user objects where the darkMode preference is enabled.

// Create the User interface
interface User {
   name: string;
   age: number;
   email: string;
   preferences: {
      theme: string;
      darkMode: boolean;
      notifications: number;
   };
}

// Create an array of User objects
const users: User[] = [
   {
      name: "John Doe",
      age: 25,
      email: "john.doe@example.com",
      preferences: {
         theme: "light",
         darkMode: true,
         notifications: 5,
      },
   },
   {
      name: "Jane Smith",
      age: 30,
      email: "jane.smith@example.com",
      preferences: {
         theme: "dark",
         darkMode: false,
         notifications: 10,
      },
   },
];

const filterMatchingObjects = (users: User[], filterValue: boolean): User[] => {
   const filteredUsers: User[] = []; 
   for (const user of users) {
      if (user.preferences.darkMode === filterValue) {
         filteredUsers.push(user);
      }
   } 
   return filteredUsers;
}; 
const usersWithDarkMode = filterMatchingObjects(users, true); 
console.log(usersWithDarkMode);

On compiling, it will generate the following JavaScript code −

// Create an array of User objects
var users = [
   {
      name: "John Doe",
      age: 25,
      email: "john.doe@example.com",
      preferences: {
         theme: "light",
         darkMode: true,
         notifications: 5
      }
   },
   {
      name: "Jane Smith",
      age: 30,
      email: "jane.smith@example.com",
      preferences: {
         theme: "dark",
         darkMode: false,
         notifications: 10
      }
   },
];
var filterMatchingObjects = function (users, filterValue) {
   var filteredUsers = [];
   for (var _i = 0, users_1 = users; _i < users_1.length; _i++) {
      var user = users_1[_i];
      if (user.preferences.darkMode === filterValue) {
         filteredUsers.push(user);
      }
   }
   return filteredUsers;
};
var usersWithDarkMode = filterMatchingObjects(users, true);
console.log(usersWithDarkMode);

Output

The above code will produce the following output −

[
   {
      name: 'John Doe',
      age: 25,
      email: 'john.doe@example.com',
      preferences: { theme: 'light', darkMode: true, notifications: 5 }
   }
]

Example 3

In this example, we have created a file system represented by a nested object structure. Each object in the file system has a name property and an optional children property that contains an array of nested file system objects.

After defining the file system structure, we implement the filterMatchingObjects function. This function recursively filters the file system objects and their children based on a specified filter value. It creates a new object called filteredObj to store the filtered result.

To perform the filtering, the function checks if the current object has children. If it does, it iterates over each child, recursively calling the filterMatchingObjects function on them. It then filters out any null values, keeping only the filtered children. If there are filtered children, they are added to the filteredObj.

The function also checks if the current object's name matches the filter value or if it has any filtered children. If either condition is true, the filteredObj is returned. Otherwise, null is returned.

Users can observe the output to see that the filteredFileSystem object only contains the file system objects that match the filter value "file6.txt" and their exact same children.

interface FileSystemObject {
   name: string;
   children?: FileSystemObject[];
} 
function filterMatchingObjects(obj: FileSystemObject, filterValue: string): FileSystemObject | null {
   const filteredObj: FileSystemObject = { name: obj.name }; 
   if (obj.children) {
      const filteredChildren: FileSystemObject[] = obj.children
      .map(child => filterMatchingObjects(child, filterValue))
      .filter(child => child !== null) as FileSystemObject[]; 
      if (filteredChildren.length > 0) {
         filteredObj.children = filteredChildren;
      }
   } 
   if (obj.name === filterValue || (filteredObj.children && filteredObj.children.length > 0)) {
      return filteredObj;
   }
   return null;
} 

// Example usage
const fileSystem: FileSystemObject = {
   name: "root",
   children: [
      {
         name: "folder1",
         children: [
            { name: "file1.txt" },
            { name: "file2.txt" },
            { name: "file3.ts" }
         ]
      },
      {
         name: "folder2",
         children: [
            { name: "file4.js" },
            { name: "file5.ts" },
            { name: "file6.txt" }
         ]
      }
   ]
}; 
const filteredFileSystem = filterMatchingObjects(fileSystem, "file6.txt");
console.log(filteredFileSystem);

On compiling, it will generate the following JavaScript code −

function filterMatchingObjects(obj, filterValue) {
   var filteredObj = { name: obj.name };
   if (obj.children) {
      var filteredChildren = obj.children
      .map(function (child) { return filterMatchingObjects(child, filterValue); })
      .filter(function (child) { return child !== null; });
      if (filteredChildren.length > 0) {
         filteredObj.children = filteredChildren;
      }
   }
   if (obj.name === filterValue || (filteredObj.children && filteredObj.children.length > 0)) {
      return filteredObj;
   }
   return null;
}
// Example usage
var fileSystem = {
   name: "root",
   children: [
      {
         name: "folder1",
         children: [
            { name: "file1.txt" },
            { name: "file2.txt" },
            { name: "file3.ts" }
         ]
      },
      {
         name: "folder2",
         children: [
            { name: "file4.js" },
            { name: "file5.ts" },
            { name: "file6.txt" }
         ]
      }
   ]
};
var filteredFileSystem = filterMatchingObjects(fileSystem, "file6.txt");
console.log(filteredFileSystem);

Output

The above code will produce the following output −

{ name: 'root', children: [ { name: 'folder2', children: [Array] } ] }

In this tutorial, users learned how to filter all matching objects in an object, and it's exactly the same children using Typescript. By using the recursive function & filter method, we can easily search through large objects and extract the data we need. This can be especially helpful in large web applications where data management is crucial.

Updated on: 21-Aug-2023

714 Views

Kickstart Your Career

Get certified by completing the course

Get Started
Advertisements