skip to Main Content

I have this data

  const data = [
    {
      name: "Car",
      id: "19",
      count: "20",
      depth: "1",
      children: [
        {
          name: "Wheel",
          id: "22",
          count: "3",
          depth: "2",
          children: [
            {
              name: "Engine",
              id: "101",
              count: "1",
              depth: "3",
              children: [
                {
                  name: "Engine and Brakes",
                  id: "344",
                  count: "1",
                  depth: "4",
                  children: []
                }
              ]
            }
          ]
        }
      ]
    },
    {
      name: "Bike",
      id: "3",
      count: "12",
      depth: "1",
      children: [
        {
          name: "SpeedBike",
          id: "4",
          count: "12",
          depth: "2",
          children: []
        }
      ]
    }
  ];

I want to pass in multiple category ids as follows [’22’, ‘3’] and be able to get all the children of the passed category ids which should look like this:


[
  {
    name: "Engine",
    id: "101",
    count: "1",
  },
  {
    name: "Engine and Brakes",
    id: "344",
    count: "1",
  },
  {
    name: "SpeedBike",
    id: "4",
    count: "12",
  }
]

If no category id is passed I want to be able to see the parent and the direct children as default. like below:

[
 {  
    name: "Car",
    id: "19",
    count: "20"
 },
 {
    name: "Wheel",
    id: "22",
    count: "3"
 },
 {
    name: "Bike",
    id: "3",
    count: "12",
 },
 {
    name: "SpeedBike",
    id: "4",
    count: "12"
 }
]

If the category id passed does not have children I want to return an empty array.:

[]

I want to avoid using for foreach and while. How can I achieve this? I have tried using map and filter but no luck. Can someone please help? What is the best approach to this?

I am using js and ts.

The nested array can be deep with multiple deep levels.

3

Answers


  1. Below is a simple reference for you to using Recursive_function to do it

    const data = [
        {
          name: "Car",
          id: "19",
          count: "20",
          depth: "1",
          children: [
            {
              name: "Wheel",
              id: "22",
              count: "3",
              depth: "2",
              children: [
                {
                  name: "Engine",
                  id: "101",
                  count: "1",
                  depth: "3",
                  children: [
                    {
                      name: "Engine and Brakes",
                      id: "344",
                      count: "1",
                      depth: "4",
                      children: []
                    }
                  ]
                }
              ]
            }
          ]
        },
        {
          name: "Bike",
          id: "3",
          count: "12",
          depth: "1",
          children: [
            {
              name: "SpeedBike",
              id: "4",
              count: "12",
              depth: "2",
              children: []
            }
          ]
        }
      ];
     
    
    const searchData = (arr,categories=[],matched = false) => {
        let result = []
        for(a of arr){
            let includes = matched ? true: categories.includes(a.id)
            if(includes || matched){
                result.push(...a.children)
            }
            result.push(...searchData(a.children,categories,includes))
        }
        return result;
    }
    
    const filterData = (arr,categories=[]) => {
        let result = []
        if(!!categories && categories.length > 0){
            result = searchData(arr,categories)
        } else {
            for(a of arr){
                result.push(a,...a.children)
            }
        }
        result = result.map(({id,name,count,...reset})=> ({id,name,count}))
        return result
    }
    
    console.log(filterData(data,[]))
    console.log("--------------------")
    console.log(filterData(data,["3","22"]))
    Login or Signup to reply.
  2. We are still going to use the approach described in your previous related question. However, we are going to update the algorithm slightly.

    Now stack will store categories with additional isDesired?: boolean prop, which indicates that this category is the descendant of the category with the id that we are looking for.
    If the category’s id is in categoryIds then we push its children in the stack with the isDesired: true.
    We decide to put children of category into foundChildren under the condition: if the category id is in categoryIds or category.isDesired is true

    const mapCategory = (category: Category) => ({
      name: category.name,
      id: category.id,
      count: category.count,
    });
    
    const getCategoriesChildren = (
      categoryIds: Category['id'][],
      categories: Category[],
    ) => {
      const foundChildren: Pick<Category, 'id' | 'count' | 'name'>[] = [];
    
      if (categoryIds.length === 0) {
        return categories.reduce<Pick<Category, 'id' | 'count' | 'name'>[]>(
          (acc, category) => {
            acc.push(mapCategory(category), ...category.children.map(mapCategory));
            return acc;
          },
          [],
        );
      }
    
      const stack: (Category & { isDesired?: boolean })[] = [...categories];
    
      while (stack.length) {
        const category = stack.pop();
        if (!category) continue;
    
        const isDesiredCategory =
          categoryIds.includes(category.id) || category.isDesired;
    
        if (isDesiredCategory) {
          foundChildren.push(...category.children.map(mapCategory));
        }
    
        stack.push(
          ...(isDesiredCategory
            ? category.children.map((child) => ({ ...child, isDesired: true }))
            : category.children),
        );
      }
    
      return foundChildren;
    };
    

    Playground with comments

    Login or Signup to reply.
  3. Call this function –

    function GetFilteredOrNonFilteredData(data, stringofids = [])
    {
    const resolvedData = GetData(data);
    if (stringofids.length <= 0) {
        return resolvedData.map(item => {
            delete item.parentid;
            delete item.depth;
            delete item.children;
            return item
        });
    }
    return resolvedData.filter((item) => {
        
        if(stringofids.includes(item.parentid)){
            delete item.parentid;
            delete item.depth;
            delete item.children;
            return item
        };
    })
    }
    

    Include this function in the file –

    function GetData(data, id = 0) {
    const allData = [];
    
    function processItem(item, parentId) {
        item.parentid = parentId;
        allData.push(item);
        if (item.children.length > 0) {
            item.children.forEach(child => processItem(child, item.id));
        }
    }
    
    data.forEach(item => {
        processItem(item, id);
    });
    
    return allData;
    }
    

    Example –

    console.log(GetFilteredOrNonFilteredData(data,["101","22"]));
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search