1

I have list of tree node metadataList Like below:

   [
  {
    "data": {
      "metadata": {
        "category": [
          "Csp"
        ]
      }
    },
    "children": [
      {
        "data": {
          "metadata": {
            "category": [
              "Csp"
            ]
          }
        },
        "children": [

        ]
      },
      {
        "data": {
          "metadata": {
            "category": [
              "Mpn"
            ]
          }
        },
        "children": [

        ]
      },
      {
        "data": {
          "metadata": {
            "category": [
              "Mpn"
            ]
          }
        },
        "children": [

        ]
      },
      {
        "data": {
          "metadata": {
            "category": [
              "Mpn"
            ]
          }
        },
        "children": [

        ]
      }
    ]
  },
  {
    "data": {
      "metadata": {
        "category": [
          "Isv"
        ]
      }
    },
    "children": [
      {
        "data": {
          "metadata": {
            "category": [
              "Isv"
            ]
          }
        },
        "children": [

        ]
      },
      {
        "data": {
          "metadata": {
            "category": [
              "Isv"
            ]
          }
        },
        "children": [

        ]
      }
    ]
  },
  {
    "data": {
      "metadata": {
        "category": [
          "Csp"
        ]
      }
    },
    "children": [
      {
        "data": {
          "metadata": {
            "category": [
              "Csp"
            ]
          }
        },
        "children": [

        ]
      }
    ]
  },
  {
    "data": {
      "metadata": {
        "category": [
          "Mpn"
        ]
      }
    },
    "children": [
      {
        "data": {
          "metadata": {
            "category": [
              "Mpn"
            ]
          }
        },
        "children": [

        ]
      },
      {
        "data": {
          "metadata": {
            "category": [
              "Mpn"
            ]
          }
        },
        "children": [

        ]
      },
      {
        "data": {
          "metadata": {
            "category": [
              "Mpn"
            ]
          }
        },
        "children": [

        ]
      },
      {
        "data": {
          "metadata": {
            "category": [
              "Csp"
            ]
          }
        },
        "children": [

        ]
      },
      {
        "data": {
          "metadata": {
            "category": [
              "Isv"
            ]
          }
        },
        "children": [

        ]
      }
    ]
  },
  {
    "data": {
      "metadata": {
        "category": [
          "Incentives"
        ]
      }
    },
    "children": [
      {
        "data": {
          "metadata": {
            "category": [
              "Incentives"
            ]
          }
        },
        "children": [

        ]
      }
    ]
  }
]

Which is a type of array of data and children collection it's class like below:

export default class CurrentTopicMetadataTreeNode {
    public data: CurrentTopicMetadata;
    public children: CurrentTopicMetadataTreeNode[];
}

export default class CurrentTopicMetadata {
    public id: string;
    public metadata: TopicMetadata 

}

export class TopicMetadata {
    public category: Category[] 

}

export enum Category {
    Csp = 'Csp',
    Mpn = 'Mpn',
    Incentives = 'Incentives',
    Referrals = 'Referrals',
    Isv = 'Isv',

}

What I am trying, to filter list as data and children order as per category. Let say if filter by a category all data and children belongs to that category should come like below order.

enter image description here

But I am getting data like this order :

enter image description here

One Element On Array Problem Set:

Here in this array if I search with Csp Only data in root node which is Csp and data in children only has one data which contains Csp would be in array.

[{
    "data": {
      "metadata": {
        "category": [
          "Csp"
        ]

      }


    },
    "children": [
      {
        "data": {

          "metadata": {
            "category": [
              "Csp"
            ]

          }



        },
        "children": [

        ]
      },
      {
        "data": {

          "metadata": {
            "category": [
              "Mpn"
            ]
          }



        },
        "children": [

        ]
      },
      {
        "data": {

          "metadata": {
            "category": [
              "Mpn"
            ]
          }

        },
        "children": [

        ]
      },
      {
        "data": {

          "metadata": {
            "category": [
              "Mpn"
            ]

          }

        },
        "children": [

        ]
      }
    ]
  }]

Expected Output: So after filtered by Csp node should be look like this:

[
  {
    "data": {
      "metadata": {
        "category": [
          "Csp"
        ]
      }
    },
    "children": [
      {
        "data": {
          "metadata": {
            "category": [
              "Csp"
            ]
          }
        },
        "children": [

        ]
      }
    ]
  }
]

here is my code, where I am doing wrong?

// Rule 1 check parent metadata category whether be empty

// Rule 2 and 3
function find_in_children(children, parent_category) {
    children_has_same_category = []
    for(var i in children) {
        let child = children[i];
        if(child.children != undefined && child.children.length > 0 && child.data.metadata.category == parent_category) {
            children_has_same_category.push(child);
        }
    }
    if(children_has_same_category.length > 0) {
        return children_has_same_category
    } else {
        for(var i in children) {
            let child = children[i];
            return find_in_children(child.children, parent_category);
        }
    }
}

function check_object(object) {
    let parent_category = object.data.metadata.category[0];
    if(object.children != undefined && object.children.length > 0) {
        return {'data': object.data, 'children': find_in_children(object.children, parent_category)}
    } else {
        return {'data': object.data}
    }
}

function apply_rules(object) {
    // Rule 1 check parent metadata category whether be empty
    if(object.data.metadata.category.length > 0) {
        return {'data': object.data}
    } else {
        return check_object(object)
    }
}

 target = {
    value: 'Isv'
}
filtered_datas = []
for(var i in datas) {
    let data = datas[i];
    if(data.data.metadata.category.length > 0) {
        result = apply_rules(data)
        if(result.data.metadata.category[0] == target.value) {
            filtered_datas.push(result);
        }
    }
}

Here is the data sample and result: https://jsfiddle.net/faridkiron/b02cksL8/#&togetherjs=F7FK3fBULx

Another Recursive Function I have tried:

   handleRecursiveParentChildNode(parent: CurrentTopicMetadataTreeNode, searchKey) {

        let result = parent;
        result.children = [];
        if (parent.children.length > 0) {
            parent.children.forEach(child => {
                let childData = this.handleRecursiveParentChildNode(child, searchKey);

                if (childData.data && childData.data != undefined)
                    result.children.push(childData);
            });
            let cate = parent.data.metadata.category.filter(cat => cat === searchKey);
            if (!result.children && cate.length < 1) {
                result = null;
            }
        }
        else {
            let cate = parent.data.metadata.category.filter(cat => cat === searchKey);
            if (cate.length < 1) {
                result = null;
            }
        }
        return result;
    }
7
  • What should I do? Commented May 25, 2020 at 6:04
  • remove all the properties which are not meaningful for our problem "namePath", "reportingProblem", etc. Show an exemple output not in picture but in text (in your picture we don't know the content of data and children so we don't know what you filtered) Commented May 25, 2020 at 6:07
  • 1
    Updated the question as per your suggestion. Hope it is readable now. Commented May 25, 2020 at 6:40
  • 1
    I answered based on what I have understood of the problem. Order and sort appears in your post so I am not sure whether you want to filter out nodes which don't match your type, or if you want to sort the list with nodes which matches your type first (you went a bit too aggresive by deleting the id which were useful to identify your nodes) Commented May 25, 2020 at 7:30
  • Thanks for the answer, yes on first approach I did it but on next recursive method I am trying to filter the nodes which meet my search Key. Only. I am checking yours too. Thanks once again. Could you please point me handleRecursiveParentChildNode what is my mistake? Few problem there. I am very closed. Commented May 25, 2020 at 7:35

2 Answers 2

1

You can filter the data with Array.prototype.filter

const data = [{"data":{"metadata":{"category":["Csp"]}},"children":[{"data":{"metadata":{"category":["Csp"]}},"children":[]},{"data":{"metadata":{"category":["Mpn"]}},"children":[]},{"data":{"metadata":{"category":["Mpn"]}},"children":[]},{"data":{"metadata":{"category":["Mpn"]}},"children":[]}]},{"data":{"metadata":{"category":["Isv"]}},"children":[{"data":{"metadata":{"category":["Isv"]}},"children":[]},{"data":{"metadata":{"category":["Isv"]}},"children":[]}]},{"data":{"metadata":{"category":["Csp"]}},"children":[{"data":{"metadata":{"category":["Csp"]}},"children":[]}]},{"data":{"metadata":{"category":["Mpn"]}},"children":[{"data":{"metadata":{"category":["Mpn"]}},"children":[]},{"data":{"metadata":{"category":["Mpn"]}},"children":[]},{"data":{"metadata":{"category":["Mpn"]}},"children":[]},{"data":{"metadata":{"category":["Csp"]}},"children":[]},{"data":{"metadata":{"category":["Isv"]}},"children":[]}]},{"data":{"metadata":{"category":["Incentives"]}},"children":[{"data":{"metadata":{"category":["Incentives"]}},"children":[]}]}]
const dfs = (iNode, type) => {
  const node = Object.assign({}, iNode) // shallow copy current node
  node.children = iNode.children.flatMap(child => {
    // if child matches type, return it, otherwise filter it out
    return child.data.metadata.category.includes(type) ? dfs(child, type) : []
  })
  return node
}

// fakes a root node to apply dfs on
const cspList = dfs({ children: data }, 'Csp').children
console.log(JSON.stringify(cspList, null, 2))

edit: in case flatMap can't be used (for some reasons) it is possible to use filter + map

const data = [{"data":{"metadata":{"category":["Csp"]}},"children":[{"data":{"metadata":{"category":["Csp"]}},"children":[]},{"data":{"metadata":{"category":["Mpn"]}},"children":[]},{"data":{"metadata":{"category":["Mpn"]}},"children":[]},{"data":{"metadata":{"category":["Mpn"]}},"children":[]}]},{"data":{"metadata":{"category":["Isv"]}},"children":[{"data":{"metadata":{"category":["Isv"]}},"children":[]},{"data":{"metadata":{"category":["Isv"]}},"children":[]}]},{"data":{"metadata":{"category":["Csp"]}},"children":[{"data":{"metadata":{"category":["Csp"]}},"children":[]}]},{"data":{"metadata":{"category":["Mpn"]}},"children":[{"data":{"metadata":{"category":["Mpn"]}},"children":[]},{"data":{"metadata":{"category":["Mpn"]}},"children":[]},{"data":{"metadata":{"category":["Mpn"]}},"children":[]},{"data":{"metadata":{"category":["Csp"]}},"children":[]},{"data":{"metadata":{"category":["Isv"]}},"children":[]}]},{"data":{"metadata":{"category":["Incentives"]}},"children":[{"data":{"metadata":{"category":["Incentives"]}},"children":[]}]}]
const dfs = (iNode, type) => {
  const node = Object.assign({}, iNode) // shallow copy current node
  node.children = iNode.children
    .filter(child => child.data.metadata.category.includes(type))
    .map(child => dfs(child, type))
  return node
}

// fakes a root node to apply dfs on
const cspList = dfs({ children: data }, 'Csp').children
console.log(JSON.stringify(cspList, null, 2))


regarding errors in original code

handleRecursiveParentChildNode(parent: CurrentTopicMetadataTreeNode, searchKey) {

    let result = parent;
    result.children = [];
    // bug? since we are called from parent we obviously are a children
    // so else block is never run
    if (parent.children.length > 0) {
        parent.children.forEach(child => {
            let childData = this.handleRecursiveParentChildNode(child, searchKey);

            // bug ? we never filter out children and push every one of them on result
            if (childData.data && childData.data != undefined)
                result.children.push(childData);
        });
        // bug ? !result.children is never truthy (![] === false)
        // so if is never run
        let cate = parent.data.metadata.category.filter(cat => cat === searchKey);
        if (!result.children && cate.length < 1) {
            result = null;
        }
    }
    // never run
    else {
        let cate = parent.data.metadata.category.filter(cat => cat === searchKey);
        if (cate.length < 1) {
            result = null;
        }
    }
    return result;
}
Sign up to request clarification or add additional context in comments.

7 Comments

Nice finding I didn't think in that way. I am playing with your answer.
In this line return child.data.metadata.category.includes(type) ? dfs(child, type) : [] you have placed a empty array once the category empty which creates a [] array list on output when I tried with Incentives I cannot eliminate it from list this there any other way to remove it ?
I have replace that with '' then filter it like const arrFiltered = cspList.filter(el => { return el != null && el != ''; });.
if output is [] it means none of the children was matching Incentives which what we desire? If you are not comfortable with flatMap, you can use the classic filter: v = children.filter(c => c.data.metadata.category.includes(type)) which keep only the child you are insteresteded, then node.children = v.map(//and you apply dfs here) . Do not hesitate to ask me if you are still stuck on this @MdFaridUddinKiron
No, I found flatMap is little efficient. no problem with that. Thanks for your response.
|
1

You can use recursive call reduce for filter your data:

const filterItems = (items, f) => {
  const fitems = items.reduce((acc, rec) => {
      const children = rec.children.length > 0 ? filterItems(rec.children, f): []
      if (rec.data.metadata.category.indexOf(f) >= 0) {
        return [...acc, {...rec, children}]
      }
      return [...acc]
  }, [])
  return fitems
}

7 Comments

What is items and f here?
f - filter (search string). In you case f='Csp' as example
Thanks for the explanation. But the output is not correct. You could have a look here
You can see example in playground. In output i have items where root node with 'Csp' or childs nodes with 'Csp': jscomplete.com/playground/s499761
I have checked, when search with Csp there is a element from Mpn on parent which is not correct. that should be eliminate from new array list.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.