繁体   English   中英

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

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

我有一个这样的 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可能需要一些额外的逻辑来处理兄弟姐妹,但这应该是一个不错的起点。

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

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)。
  • 该解决方案基于假设,如果当前节点的级别更高,则前一个节点是当前节点的父节点。
  • “父相邻节点”只是层次结构中较高的节点,但不是当前节点的直接父节点(我认为它是叔叔/阿姨)。 如果你有更好的名字,请分享你的建议。
  • 在我的场景中,根节点的级别为 0。然而,在提问者的场景中,根节点的级别为 1。
  • 我正在使用递归来附加父相邻节点。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM