【问题标题】:Parent and Child array sorting doesn't working accordingly父子数组排序不起作用
【发布时间】:2020-05-25 05:15:38
【问题描述】:

我有树节点列表metadataList 如下:

   [
  {
    "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": [

        ]
      }
    ]
  }
]

这是datachildren 集合的数组类型,它的类如下:

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',

}

我正在尝试按类别将列表过滤为datachildren 顺序。假设如果按类别过滤所有数据和属于该类别的子项应该如下所示。

但我得到这样的数据:

One Element On Array Problem Set:

如果我使用Csp 搜索,则在此数组中只有根节点中的数据Cspchildren 中的数据只有一个包含datadata 将在数组中。

[{
    "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: 所以经过Csp节点过滤后应该是这样的:

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

        ]
      }
    ]
  }
]

这是我的代码,我哪里做错了?

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

这是数据样本和结果:https://jsfiddle.net/faridkiron/b02cksL8/#&togetherjs=F7FK3fBULx

我尝试过的另一个递归函数:

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

【问题讨论】:

  • 我该怎么办?
  • 删除所有对我们的问题“namePath”、“reportingProblem”等没有意义的属性。显示一个示例输出不是在图片中,而是在文本中(在你的图片中我们不知道内容数据和孩子,所以我们不知道你过滤了什么)
  • 根据您的建议更新了问题。希望它现在可以阅读。
  • 我是根据我对问题的理解回答的。排序和排序出现在您的帖子中,因此我不确定您是要过滤掉与您的类型不匹配的节点,还是要先使用与您的类型匹配的节点对列表进行排序(您有点过于激进了删除有助于识别节点的 id)
  • 感谢您的回答,是的,在第一种方法中我做到了,但在下一个递归方法中,我试图过滤符合我的搜索键的节点。仅有的。我也在检查你的。再次感谢。你能指点我handleRecursiveParentChildNode我的错误是什么吗?那里没什么问题。我很封闭。

标签: javascript typescript


【解决方案1】:

您可以使用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))

编辑:如果 flatMap 不能使用(由于某些原因),可以使用 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))

关于原始代码中的错误

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

【讨论】:

  • 很高兴发现我没有那样想。我在玩你的答案。
  • return child.data.metadata.category.includes(type) ? dfs(child, type) : [] 这一行中,一旦类别为空,当我尝试使用Incentives 时,您已经放置了一个空数组,它会在输出上创建一个[] 数组列表我无法从列表中删除它有任何其他删除方法?
  • 我已将其替换为 '',然后像 const arrFiltered = cspList.filter(el =&gt; { return el != null &amp;&amp; el != ''; }); 一样过滤它。
  • 如果输出是 [] 这意味着没有孩子匹配我们想要的奖励?如果您对 flatMap 不满意,可以使用经典过滤器:v = children.filter(c =&gt; c.data.metadata.category.includes(type)) 只保留您感兴趣的孩子,然后是 node.children = v.map(//and you apply dfs here) 。不要犹豫,问我你是否仍然坚持这个@MdFaridUddinKiron
  • 不,我发现flatMap 效率很低。没问题。感谢您的回复。
【解决方案2】:

您可以使用递归调用 reduce 来过滤您的数据:

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
}

【讨论】:

  • 这里的itemsf 是什么?
  • f - 过滤器(搜索字符串)。在你的情况下 f='Csp' 作为例子
  • 感谢您的解释。但是输出不正确。你可以看看here
  • 您可以在操场上查看示例。在输出中,我有带有“Csp”的根节点或带有“Csp”的子节点的项目:jscomplete.com/playground/s499761
  • 我已经检查过,当使用 Csp 搜索时,父级上的 Mpn 中有一个元素不正确。应该从新数组列表中删除。
猜你喜欢
  • 2017-11-08
  • 2013-12-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-09-21
  • 1970-01-01
  • 1970-01-01
  • 2021-09-27
相关资源
最近更新 更多