简体   繁体   中英

Parent and Child array sorting doesn't working accordingly

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.

在此处输入图像描述

But I am getting data like this order:

在此处输入图像描述

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;
    }

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;
}

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
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM