【问题标题】:JavaScript: Convert linear JSON array into tree structure with unknown depthJavaScript:将线性 JSON 数组转换为深度未知的树结构
【发布时间】:2014-11-08 10:05:17
【问题描述】:

我有一个这样的 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,未知

【问题讨论】:

  • 到目前为止你尝试过什么?在 SO 上,人们希望你至少花 5 分钟来解决你的问题,如果你真的在某个时候卡住了,那就问一个问题。没有你展示你的努力并要求人们为你编写代码是不好的,你永远不会自己学习任何东西。
  • 我试过写很多函数,尝试了很多方法,但都失败了。我意识到的一件事是,这只能通过编写递归函数来实现。请帮忙。
  • 那么我建议您发布您最好的努力之一,或者至少是最后的努力。否则,您的帖子将在您意识到之前被关闭并投反对票。
  • 好的,保存通常的“发表你的努力”评论。你怎么“a”是“d”的父母。我应该假设最近的前一个是父母吗?如果你之前有 2 级,然后有 4 级,但没有 3 级,会发生什么?
  • @Raghavendra 你如何决定f 和g 应该是e 还是a 的孩子?正如定义的那样,这个问题对我来说听起来模棱两可......

标签: javascript data-structures recursive-datastructures


【解决方案1】:

这里是一个快速的开始:

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

【讨论】:

    【解决方案2】:

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

    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。
    • 我正在使用递归来追加父相邻节点。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-08-03
      • 1970-01-01
      • 2017-10-01
      • 1970-01-01
      • 2021-08-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多