javascript - 将带有项目的路径转换为树对象
问题描述
我正在尝试将包含路径的对象数组转换为数据树,因此我在路径上编写了一个函数路径循环:
从这个数组:
[ { userName: "1", tags: ["A;B"] }, { userName: "2", tags: ["A;B"] }, { userName: "3", tags: ["A;"] }, { userName: "4", tags: ["A;B;C"] }, { userName: "5", tags: ["A;B"] }, { userName: "6", tags: ["A;B;C;D"] } ]
到这个结构:
[{ name: "A", families: [{ name: "B", families: [{ name: "C", families: [{ name: "D", families: [], items: ["6"] }], items: ["4"] }], items: ["1", "2", "5"] }], items: ["3"] }]
function convertListToTree(associationList) {
let tree = [];
for (let i = 0; i < associationList.length; i++) {
let path = associationList[i].tags[0].split(';');
let assetName = associationList[i].userName;
let currentLevel = tree;
for (let j = 0; j < path.length; j++) {
let familyName = path[j];
let existingPath = findWhere(currentLevel, 'name', familyName);
if (existingPath) {
if (j === path.length - 1) {
existingPath.items.push(assetName);
}
currentLevel = existingPath.families;
} else {
let assets = [];
if (j === path.length - 1) {
assets.push(assetName)
}
let newPart = {
name: familyName,
families: [],
items: assets,
};
currentLevel.push(newPart);
currentLevel = newPart.families;
}
}
}
return tree;
}
function findWhere(array, key, value) {
let t = 0;
while (t < array.length && array[t][key] !== value) {
t++;
}
if (t < array.length) {
return array[t]
} else {
return false;
}
}
但是我在这里有一些问题,即预期的输出不像我想要的那样
[
{
"name": "A",
"families": [
{
"name": "B",
"families": [
{
"name": "C",
"families": [
{
"name": "D",
"families": [],
"items": [
"6"
]
}
],
"items": [
"4"
]
}
],
"items": [
"1",
"2",
"5"
]
},
{
"name": "",
"families": [],
"items": [
"3"
]
}
],
"items": []
}
]
有人可以帮我解决这个问题吗
解决方案
请允许我做两个小改动,ramdamergeDeepWithKey
将为您完成大部分工作。
更改,在我们开始之前:
- 制作
tags
一个数组而不是一个包含一个字符串的数组(即tags[0].split(";")
) - 允许家庭成为类似字典的对象而不是数组(如果您需要数组格式,它是
Object.values(dict)
)
解决方案:
- 使用将每个条目转换为所需格式的路径
reduce
- 使用自定义逻辑合并所有路径:
- 合并
name
条目时,不要更改name
- 合并
items
条目时,连接
- 合并
const inp = [
{ userName: "1", tags: ["A","B"] },
{ userName: "2", tags: ["A","B"] },
{ userName: "3", tags: ["A"] },
{ userName: "4", tags: ["A","B","C"] },
{ userName: "5", tags: ["A","B"] },
{ userName: "6", tags: ["A","B","C","D"] }
];
// Transform an input element to a nested path of the right format
const Path = ({ userName, tags }) => tags
.slice(0, -1)
.reduceRight(
(families, name) => ({ name, families: { [families.name]: families },
items: []
}),
({ name: last(tags), families: {}, items: [userName] })
);
// When merging path entries, use this custom logic
const mergePathEntry = (k, v1, v2) =>
k === "name" ? v1 :
k === "items" ? v1.concat(v2) :
null;
const result = inp
.map(Path)
// Watch out for inp.length < 2
.reduce(
mergeDeepWithKey(mergePathEntry)
)
console.log(JSON.stringify(result, null, 2));
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.min.js"></script>
<script>const { mergeDeepWithKey, last } = R;</script>
推荐阅读
- javascript - 为什么运算符 forkJoin 不起作用?
- php - 将 orderBy ('created_at', 'desc') 添加到我的帐户
- ios - 单元格出屏时多次调用UITableView
- python - conda 虚拟环境不适用于 pycharm
- scala - ChannelOutboundBuffer 分配超过 2GB 并 OOMing 我的执行程序
- java - 如何在 rxjava 中实现一个被中断的线程?
- reactjs - 用道具重构
- android - 谷歌地图拒绝显示
- javascript - 无需 ajax 或 api 集成前端和后端的最佳方法
- python - 如何在熊猫数据框中使用 0 值进行日志记录