javascript - 父子数组排序不起作用
问题描述
我有树节点列表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": [
]
}
]
}
]
这是一种数组类型,data
它children
的类如下所示:
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',
}
我正在尝试按类别过滤列表data
和排序。children
假设如果按类别过滤所有数据和属于该类别的子项应该如下所示。
但我得到这样的数据:
One Element On Array Problem Set:
在这个数组中,如果我使用Csp
Only data in root node which is搜索Csp
并且数据中children
只有一个data
包含Csp
将在数组中。
[{
"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;
}
解决方案
您可以使用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;
}
推荐阅读
- unix - 使用 tr 只转换空格,而不是制表符或换行符
- sql-server - Detaching a database as a backup strategy
- angular - 在 Angular 中,将构造函数置于类变量之上是否可以/合适?
- openapi - Can we use allOf in OpenAPI /components/parameters to override attributes of a referenced parameter?
- google-api - Vision API:如何获取 JSON 输出
- r - 超过一个额外变量的两个以上变量的直方图
- java - LocalDateTime 默认不是 ISO8601
- javascript - Validator.js - 如何在 NodeJS 中验证字母数字密码?
- python - def 主打印列表经过多个子程序后如何制作?
- sql - 动态设置 ansi_nulls 和quoted_identifier