Javascript 将包含项的路径转换为树对象
我试图将一个包含路径的对象数组转换为数据树,因此我在路径上编写了一个函数路径循环: 从该阵列:Javascript 将包含项的路径转换为树对象,javascript,node.js,json,ramda.js,Javascript,Node.js,Json,Ramda.js,我试图将一个包含路径的对象数组转换为数据树,因此我在路径上编写了一个函数路径循环: 从该阵列: [ {用户名:“1”,标签:[“A;B”]}, {用户名:“2”,标签:[“A;B”]}, {用户名:“3”,标记:[“A;”]}, {用户名:“4”,标签:[“A;B;C”]}, {用户名:“5”,标签:[“A;B”]}, {用户名:“6”,标签:[“A;B;C;D”] ] 对于该结构: [{ 名称:“A”, 家庭:[{ 名称:“B”, 家庭:[{ 名称:“C”, 家庭:[{ 名称:“D”, 家庭
[
{用户名:“1”,标签:[“A;B”]},
{用户名:“2”,标签:[“A;B”]},
{用户名:“3”,标记:[“A;”]},
{用户名:“4”,标签:[“A;B;C”]},
{用户名:“5”,标签:[“A;B”]},
{用户名:“6”,标签:[“A;B;C;D”]
]
对于该结构:
[{
名称:“A”,
家庭:[{
名称:“B”,
家庭:[{
名称:“C”,
家庭:[{
名称:“D”,
家庭:[],
项目:[“6”]
}],
项目:[“4”]
}],
项目:[“1”、“2”、“5”]
}],
项目:[“3”]
}]
有人能帮我解决这个问题吗?您应该能够使用递归来实现这一点,使用在每个级别调用的getFamilies和getUsers函数:
const allTags=[“A”、“B”、“C”、“D”];
设a=[{“用户名”:“1”,“标记”:[“a;B”]},{“用户名”:“2”,“标记”:[“a;B”]},{“用户名”:“3”,“标记”:[“a;”]},{“用户名”:“4”,“标记”:[“a;B;C”]},{“用户名”:“5”,“标记”:[“a;B”]},{“用户名”:“6”,“标记”:[“a;B;C;D”};
//此函数假定顺序不重要,如果重要,请删除sort()调用。
函数数组相等(a1,a2){
返回a1.length==a2.length&&a1.sort().every(函数(值,索引){返回值===a2.sort()[index]});
}
函数getUserName(标记、arr){
返回arr.filter(v=>arraysEqual(v.tags[0].split(“;”).filter(a=>a),tags)).map({userName}=>userName);
}
函数getFamilies(标记){
如果(tags.length>=allTags.length)返回[];
const name=allTags[tags.length];
常量路径=[…标记,名称];
return[{name,families:getFamilies(path),items:getUserNames(path,a)}];
}
设res=getFamilies([]);
log('Result:',JSON.stringify(res,null,4))
这里的想法是迭代数据(reduce循环),每当映射中缺少节点时(nodesMap
),使用createBranch
递归创建节点,创建父节点(如果需要…),然后将节点分配给父节点,依此类推。最后一步是获取根路径的唯一列表(数据中的a
),并将它们从映射(树
)提取到数组中
const createBranch=([name,…tagsList],nodesMap,node)=>{
如果(!nodesMap.has(name)){//如果不在映射中,则创建节点
const node={name,families:[],items:[]};
nodesMap.set(名称、节点);
//如果不是分支的根,请创建父级。。。
if(tagsList.length)createBranch(tagsList、nodesMap、node);
};
//如果父对象将子对象指定给父对象的族
if(node)nodesMap.get(name).families.push(node);
};
const createTree=数据=>{
const tree=data.reduce((nodesMap,{userName:item,tags:[tags]})=>{
const tagsList=tags.match(//[^;]+/g).reverse();//获取分支中的所有节点并反转
const name=tagsList[0];//获取叶
如果(!nodesMap.has(name))createBranch(tagsList,nodesMap);//如果叶不存在,则创建整个分支
nodesMap.get(name).items.push(item);//将项分配给叶的项
返回节点映射;
},新地图());
//获取uniqnue根的列表
常量根=[…新集合(data.map({tags:[tags]})=>tags.split(';')[0]);
返回root.map(root=>tree.get(root));//获取根节点数组
}
const data=[{“用户名”:“1”,“标记”:[“A;B”]},{“用户名”:“2”,“标记”:[“A;B”]},{“用户名”:“3”,“标记”:[“A;”]},{“用户名”:“4”,“标记”:[“A;B;C”]},{“用户名”:“5”,“标记”:[“A;B”]},{“用户名”:“6”,“标记”:[“A;B;C;D”};
const result=createTree(数据);
控制台日志(结果)代码>
.as控制台包装{max height:100%!important;top:0;}
请允许我做两个小改动,ramda的mergeDeepWithKey
将为您完成大部分工作
更改,在开始之前:
- 将
标记设置为数组,而不是包含一个字符串的数组(即标记[0]。拆分(“;”)
)
- 允许族成为类似字典的对象,而不是数组(如果需要数组格式,则为
object.values(dict)
)
解决方案:
使用reduce
使用自定义逻辑合并所有路径:
- 合并
名称
条目时,不要更改名称
- 合并
项时
项,连接
const inp=[
{用户名:“1”,标签:[“A”,“B”]},
{用户名:“2”,标签:[“A”,“B”]},
{用户名:“3”,标签:[“A”]},
{用户名:“4”,标签:[“A”、“B”、“C”]},
{用户名:“5”,标签:[“A”,“B”]},
{用户名:“6”,标签:[“A”、“B”、“C”、“D”]}
];
//将输入元素转换为正确格式的嵌套路径
常量路径=({userName,tags})=>tags
.slice(0,-1)
1.还原右(
(families,name)=>({name,families:{[families.name]:families},
项目:[]
}),
({name:last(标记),族:{},项:[userName]})
);
//合并路径条目时,请使用此自定义逻辑
const mergePathEntry=(k,v1,v2)=>
k==“姓名”?v1:
k==“项目”?v1.concat(v2):
无效的
常量结果=inp
.map(路径)
//注意inp.length<2
.减少(
mergeDeepWithKey(mergePathEntry)
)
log(JSON.stringify(result,null,2))代码>
const{mergeDeepWithKey,last}=R代码>
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": []
}
]