根据父 ID JavaScript 将对象设为子对象 [重复]
Posted
技术标签:
【中文标题】根据父 ID JavaScript 将对象设为子对象 [重复]【英文标题】:Make object as child according to the Parent Id JavaScript [duplicate] 【发布时间】:2019-10-21 18:30:57 【问题描述】:我有以下来自API
的数据:
[
"Code": "01002",
"ParentAccountId": "01",
,
"Code": "01001001003",
"ParentAccountId": "01001001",
,
"Code": "01001004",
"ParentAccountId": "01001",
,
"Code": "02",
"ParentAccountId": null,
,
"Code": "01002001",
"ParentAccountId": "01002",
,
"Code": "02002",
"ParentAccountId": "02",
,
"Code": "02001",
"ParentAccountId": "02",
,
"Code": "01001001001",
"ParentAccountId": "01001001",
,
"Code": "03",
"ParentAccountId": null,
,
"Code": "01002002",
"ParentAccountId": "01002",
,
"Code": "03001",
"ParentAccountId": "03",
,
"Code": "01",
"ParentAccountId": null,
,
"Code": "01001001002",
"ParentAccountId": "01001001",
,
"Code": "01001002",
"ParentAccountId": "01001",
,
"Code": "01001001",
"ParentAccountId": "01001",
,
"Code": "01001003",
"ParentAccountId": "01001",
,
"Code": "01001005",
"ParentAccountId": "01001",
,
"Code": "01001",
"ParentAccountId": "01",
]
看看ParentAccountId
。
由于我需要将其传递给treeview
组件,因此我需要将其转换为如下内容:
[
"Code": "01",
"ParentAccountId": null,
"children": [
"Code": "01001",
"ParentAccountId": "01",
"children": [
"Code": "01001001",
"ParentAccountId": "01001",
"children": [
"Code": "01001001001",
"ParentAccountId": "01001001",
"children": [],
,
"Code": "01001001002",
"ParentAccountId": "01001001",
"children": [],
,
"Code": "01001001003",
"ParentAccountId": "01001001",
"children": [],
,
],
,
"Code": "01001002",
"ParentAccountId": "01001",
"children": [],
,
"Code": "01001003",
"ParentAccountId": "01001",
"children": [],
,
"Code": "01001004",
"ParentAccountId": "01001",
"children": [],
,
"Code": "01001005",
"ParentAccountId": "01001",
"children": [],
],
,
"Code": "01002",
"ParentAccountId": "01",
"children": [
"Code": "01002001",
"ParentAccountId": "01002",
"children": [],
,
"Code": "01002002",
"ParentAccountId": "01002",
"children": [],
,
],
,
],
,
"Code": "02",
"ParentAccountId": null,
"children": [
"Code": "02001",
"ParentAccountId": "02",
"children": [],
,
"Code": "02002",
"ParentAccountId": "02",
"children": [],
,
],
,
"Code": "03",
"ParentAccountId": null,
"children": [
"Code": "03001",
"ParentAccountId": "03",
"children": [],
,
],
,
]
我想根据code
将该对象作为其父对象的子对象。该方案是,如果ParentAccountId
为空,则它是***父级,如果ParentAccountId
的长度为2,那么如果ParentAccountId
的长度为5,那么它是第一级子级,那么如果@987654330,它就是第三级子级@ 长度为 8 则为 4 级子级,ParentAccountId
长度为 11 级则为 5 级子级。由于 1 级子级有 2 个长度为 ParentAccountId
,那么后续子级将具有 ParentAccountId
作为父级加号的 Code
。为了更好地理解,请看第二个,因为我的英语不是那么好。
我对逻辑感到困惑。有什么建议吗?
【问题讨论】:
【参考方案1】:您可以使用reduce
方法创建树结构来创建递归函数,在每次迭代中检查父 id 是否等于当前元素 id。
const data = ["Id":"1","Code":"01","Title":"Account 01","ParentAccountId":null,"Id":"2","Code":"02","Title":"Account 02","ParentAccountId":null,"Id":"3","Code":"01001","Title":"Account 01001","ParentAccountId":"01","Id":"4","Code":"01002","Title":"Account 01002","ParentAccountId":"01","Id":"5","Code":"01002001","Title":"Account 01002001","ParentAccountId":"01002"]
function toTree(data, pid = null)
return data.reduce((r, e) =>
if (e.ParentAccountId == pid)
const obj = ...e ;
const children = toTree(data, e.Code);
if (children.length) obj.children = children;
r.push(obj);
return r;
, [])
const result = toTree(data)
console.log(result)
【讨论】:
嘿,@nenad 你的函数更好,并且适用于我的多级数据,你能解释一下它的性能不如使用循环吗?如果没有性能问题,我会选择这个解决方案,否则我会选择循环解决方案,因为我有很多数据。【参考方案2】:所涉及的逻辑是首先尝试找到每个对象的子对象(使用filter
找到所有具有ParentAccountId
等于每个对象Code
的对象)然后过滤数据以仅返回根父母(ParentAccountId
等于 null 的对象)。
试试下面的代码。
var data = [
"Id": "1",
"Code": "01",
"Title": "Account 01",
"ParentAccountId": null
,
"Id": "2",
"Code": "02",
"Title": "Account 02",
"ParentAccountId": null
,
"Id": "3",
"Code": "01001",
"Title": "Account 01001",
"ParentAccountId": "01"
,
"Id": "4",
"Code": "01002",
"Title": "Account 01002",
"ParentAccountId": "01"
,
"Id": "5",
"Code": "01002001",
"Title": "Account 01002001",
"ParentAccountId": "01002"
]
rearrangeData = () =>
var newData = []
data.forEach((x) =>
x['children'] = data.filter((y) =>
return y.ParentAccountId === x.Code
)
var parent = data.find((y) =>
return y.Code === x.ParentAccountId
)
if (parent && parent.children)
parent.children.push(x)
else if (parent && !parent.children)
parent['children'] = [x];
else
return x
newData.push(parent)
)
var parents = newData.filter((x) =>
return x.ParentAccountId === null
)
console.log(parents);
rearrangeData()
【讨论】:
兄弟,它只适用于前两个孩子,检查我已经更新了我代码中的数据,你的代码不适用于该数据。 我编辑了代码 sn-p。现在可以了。您还可以访问 codepen here,因为 sn-p 会切断一些记录的数据。【参考方案3】:我正在等待工作中的一项任务,所以我想我会为你整理一个实现。并不是说它比链接的线程中的解决方案更好或更差 - 只是另一种实现:
const data = [
"Id": "1",
"Code": "01",
"Title": "Account 01",
"ParentAccountId": null
,
"Id": "2",
"Code": "02",
"Title": "Account 02",
"ParentAccountId": null
,
"Id": "3",
"Code": "01001",
"Title": "Account 01001",
"ParentAccountId": "01"
,
"Id": "4",
"Code": "01002",
"Title": "Account 01002",
"ParentAccountId": "01"
,
"Id": "5",
"Code": "01002001",
"Title": "Account 01002001",
"ParentAccountId": "01002"
]
function buildTree(obj)
// get all top level parents
let parents = obj.filter((o) => !o.ParentAccountId);
// loop over the parents and recursively call addChild to populate the tree
parents.forEach((p) =>
p.children = addChildren(p, obj);
);
return parents;
function addChildren(parent, obj)
// find all children for this parent
let children = obj.filter((o) => o.ParentAccountId === parent.Code)
if (children.length)
// loop over any children recursively calling this function to add nested children
children.forEach((c) =>
c.children = addChildren(c, obj);
);
return children;
else
return [];
console.log(buildTree(data));
【讨论】:
【参考方案4】:您可以遍历每个节点并构建一个 child-id 到 child 的映射。
然后,再次遍历节点,但这次查看 parent-ids 并将节点推送到父节点(如果它是子节点),或者将其添加到根列表中。此响应改编自 here,并添加了自定义密钥配置。
我还添加了一种方法来删除任何不包含子节点(即叶节点)的对象上的 children
字段。
console.log(convertListToTree(getDataList(),
idKey : 'Code',
parentIdKey : 'ParentAccountId',
pruneEmptyChildren : true
));
function convertListToTree(list, options)
options = Object.assign(
idKey : 'id',
parentIdKey : 'parentId',
childrenKey : 'children',
pruneEmptyChildren : false
, options || );
let map = , node, roots = [], i;
for (i = 0; i < list.length; i++)
map[list[i][options.idKey]] = i;
list[i][options.childrenKey] = []; // Attach a "child" reference holder
for (i = 0; i < list.length; i++)
node = list[i];
if (node[options.parentIdKey] != null)
list[map[node[options.parentIdKey]]][options.childrenKey].push(node);
else
roots.push(node);
if (options.pruneEmptyChildren)
pruneEmptyKeys(roots, options.childrenKey); // Remove empty
return roots;
function pruneEmptyKeys(tree, childKey)
let items = tree[childKey] || tree;
items.forEach(item =>
if (item[childKey].length > 0)
pruneEmptyKeys(item[childKey], childKey);
else
delete item[childKey]; // Remove empty child list
);
function getDataList()
return [
"Id": "1",
"Code": "01",
"Title": "Account 01",
"ParentAccountId": null
,
"Id": "2",
"Code": "02",
"Title": "Account 02",
"ParentAccountId": null
,
"Id": "3",
"Code": "01001",
"Title": "Account 01001",
"ParentAccountId": "01"
,
"Id": "4",
"Code": "01002",
"Title": "Account 01002",
"ParentAccountId": "01"
,
"Id": "5",
"Code": "01002001",
"Title": "Account 01002001",
"ParentAccountId": "01002"
];
.as-console-wrapper
top: 0;
max-height: 100% !important;
<!-- Adapted from: https://***.com/a/18018037/1762224 -->
【讨论】:
以上是关于根据父 ID JavaScript 将对象设为子对象 [重复]的主要内容,如果未能解决你的问题,请参考以下文章
如何根据自己的宽度而不是父 div 将 CSS 边距/填充设置为子 div?
使用 .htaccess 将 Web 根文件夹设为子文件夹?