JavaScript:将线性JSON数组转换为深度未知的树结构

JavaScript: Convert linear JSON array into tree structure with unknown depth

本文关键字:未知 深度 结构 转换 线性 JSON 数组 JavaScript      更新时间:2023-09-26

我有一个JavaScript数组,如下所示:

[{ 
   name:'a'
   level:1
 },{ 
   name:'b'
   level:2
 },{
   name:'c'
   level:3
 },{ 
   name:'d'
   level:2
 },{ 
   name:'e'
   level:1
 },{ 
   name:'f'
   level:2
 },{ 
   name:'g'
   level:2
 },{
   name: 'f',
   level: 1
 }
]

我需要将其转换为基于对象的level属性的树结构

[{
    name: 'a'
    level: 1
    children: [{
        name: 'b'
        level: 2,
        children: [{
            name: 'c',
            level: 3
        }]
    }, {
        name: 'd'
        level: 2
    }]
}, {
    name: 'e'
    level: 1,
    children: [{
        name: 'f'
        level: 2
    }, {
        name: 'g'
        level: 2
    }]
}, {
    name: 'f',
    level: 1
}]

我试过写很多函数,尝试过很多方法,但都失败了。我意识到,这只能通过编写递归函数来实现。请帮忙。

注:液位深度不限于3,未知

下面是一个快速入门:

var res = convert(a);
console.log(res);
function convert(arr) {
    return treeify(splitToSegments(arr));
}
function splitToSegments(arr) {
    var ret = [];
    var accum, segment;
    arr.forEach(function(o) {
        if (o.level === 1) {
            accum = true;
            if (segment && segment.length) {
                ret.push(segment);
            }
            segment = [o];
        } else if (accum) {
            segment.push(o);
        }
    });
    if (segment && segment.length) {
        ret.push(segment);
    }
    return ret;
}
function treeify(arr) {
    return arr.map(function(o) {
        return o.reduce(function(a, b) {
            var lastChild;
            a.children = a.children || [];
            if (a.level + 1 === b.level) {
                a.children.push(b);
            } else {
                lastChild = a.children[a.children.length - 1];
                lastChild.children = lastChild.children || [];
                lastChild.children.push(b);
            }
            return a;
        });
    });
}

注意,treeify可能需要一些额外的逻辑来处理兄弟,但它应该是一个okish起点。

我遇到了完全相同的问题,这就是我的解决方案:

function constructTree (flatList) {
const tree = [];
const clonedList = cloneDeep(flatList);
let root = {};
function append (child, parent) {
    if (Array.isArray(parent.children)) {
        parent.children.push(child);
    } else {
        parent.children = [child];
    }
    return parent;
}
function appendParentAdjacentNode (level, node, nodes) {
    if (level === 0) {
        nodes.push(node);
        return node;
    }
    while (level > 0) {
        return appendParentAdjacentNode(level - 1, node, nodes[0].children);
    }
    return node;
}
let parent;
for (let i = 0; i < clonedList.length; i++) {
    const currentNode = clonedList[i];
    const previousNode = clonedList[i - 1];
    const isRoot = currentNode.level === 0;
    if (isRoot) {
        root = currentNode;
        tree.push(root);
        continue;
    }
    const isChild = currentNode.level > previousNode.level;
    const isSibling = currentNode.level === previousNode.level;
    const isParentAdjacent = currentNode.level < previousNode.level;
    if (isChild) {
        parent = previousNode;
    }
    if (isChild || isSibling) {
        append(currentNode, parent);
    }
    if (isParentAdjacent) {
        appendParentAdjacentNode(currentNode.level - 1, currentNode, root.children);
    }
}
return tree;
}

简要说明:

  • 为了保持函数的纯粹性,我在操作输入(flatList)之前先克隆它
  • 该解决方案基于这样的假设,即如果当前节点的级别更高,则前一个节点是当前节点的父节点
  • A";父相邻节点";只是层次结构中较高的节点,但不是当前节点的直接父节点(我认为它是叔叔/阿姨)。如果你有更好的名字,请分享你的建议
  • 在我的场景中,根节点的级别为0。然而,在提问者的场景中,根节点的级别为1
  • 我正在使用递归来附加父相邻节点