如何在JavaScript中将2D数组转换为(对象)树?

如何在JavaScript中将2D数组转换为(对象)树?,javascript,arrays,object,tree,Javascript,Arrays,Object,Tree,我有一个2D数组,它以这种格式表示一棵树: [[“食品”,0],“奶制品”,1],“牛奶”,2],“低脂”,3],“黄油”,2],“奶酪”,2],“蔬菜”,1],“菠菜”,2],“肉”,1],“鱼”,2],“鲑鱼”,3],“家禽”,2] 每个项(节点)都是一个数组,其中第一个元素是名称,第二个元素是节点的级别(深度) 我需要将这个2D数组转换为嵌套的JavaScript对象,其中每个节点对象由名称(字符串)和子对象(对象数组)组成。结果应该是根对象(这里是“食物”),所有其他项都是它的子项。输入

我有一个2D数组,它以这种格式表示一棵树:

[[“食品”,0],“奶制品”,1],“牛奶”,2],“低脂”,3],“黄油”,2],“奶酪”,2],“蔬菜”,1],“菠菜”,2],“肉”,1],“鱼”,2],“鲑鱼”,3],“家禽”,2]

每个项(节点)都是一个数组,其中第一个元素是名称,第二个元素是节点的级别(深度)

我需要将这个2D数组转换为嵌套的JavaScript对象,其中每个节点对象由名称(字符串)和子对象(对象数组)组成。结果应该是根对象(这里是“食物”),所有其他项都是它的子项。输入数组总是按顺序排列的,因此可以假定第一个元素是根


最好的方法是什么,迭代还是递归

递归不是必需的。我想这就是你想要的:

function tree_from_list(list) {
    var list_node = list.shift();
    var depth = list_node[1];
    var root = {name: list_node[0], children: []};
    var tree_node;
    var cur_nodes = []; 
    cur_nodes[depth] = root;
    while (list.length > 0) {
        list_node = list.shift();
        tree_node = {name: list_node[0], children: []};
        depth = list_node[1];
        if (cur_nodes[depth - 1] === undefined)
            throw 'invalid list!';
        cur_nodes[depth - 1].children.push(tree_node);
        cur_nodes[depth] = tree_node;
    }
    return root;
}
var list = [["Food", 0], ["Dairy", 1], ["Milk", 2], ["Low-fat", 3], ["Butter", 2], ["Cheese", 2], ["Vegetables", 1], ["Spinach", 2], ["Meat", 1], ["Fish", 2], ["Salmon", 3], ["Poultry", 2]];
var tree = tree_from_list(list);
下面是一个几乎毫无意义(且效率较低)的递归解决方案:

function mktree(lis, lvl) {
    var i, el, c, itemlis = [];
    for (i = 0; el = lis[i++];) {
        if (lvl !== el[1])
            break; 
        var item = {};
        [item[el[0]], c] = mktree(lis.slice(i), lvl + 1);
        i += c - 1; // skip ahead
        itemlis.push(item);
    } 
    return [itemlis, i];
}

function lis_to_tree(arr) {
    return mktree(arr, 0, 0)[0][0];
}

var arr = [["Food", 0], ["Dairy", 1], ["Milk", 2], ["Low-fat", 3], ["2%", 3],
           ["Butter", 2], ["Cheese", 2], ["Vegetables", 1], ["Spinach", 2], 
           ["Meat", 1], ["Fish", 2], ["Salmon", 3], ["Poultry", 2]];
var tree = lis_to_tree(arr);
(请注意,这依赖于分解分配来跳过已处理的元素。您可以删除此功能,但速度会慢得多。)


我把这称为毫无意义,因为它基本上是在模仿迭代,以维护已经处理过的元素的数量,这样它就可以在列表中跳到前面。我并不是说它完全没用,因为我仍然觉得递归版本比迭代版本更容易阅读。

您如何知道节点放在哪个对象下?没有办法知道
Milk
Butter
Dairy
的结构下。@Xeon06:每个节点都在最后一个深度较低的节点下,因此
Milk
Butter
Cheese
都在
Dairy
下<菠菜是蔬菜的独生子;等等。
牛奶
黄油
,和
奶酪
都属于2级。最后一个级别1是奶制品,因此是它们的父级<代码>鱼也是2级,但在更接近的1级
之后。因此,一般来说,较高级别的节点是具有较低级别的所有节点的父节点。下一个具有相同级别编号的节点是它的兄弟节点。谢谢你,本!正是我想要的。