【问题标题】:How to convert a 2D array to a tree (of objects) in JavaScript?如何在 JavaScript 中将二维数组转换为(对象)树?
【发布时间】:2011-10-25 18:49:47
【问题描述】:

我有一个二维数组以这种格式表示一棵树:

[["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]]

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

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

使用迭代或递归的最佳方法是什么?

【问题讨论】:

  • 你怎么知道节点放在哪个对象下?没有办法知道MilkButterDairy 下使用你的结构。
  • @Xeon06:每个节点都在最后遇到的深度较低的节点之下,所以MilkButterCheese都在Dairy之下; SpinachVegetables 的唯一孩子;等
  • MilkButterCheese 都属于 2 级。最后的 1 级是 Dairy,因此是它们的父级。 Fish 也是 2 级,但在更接近的 1 级 Meat 之后。因此,一般来说,较高级别的节点是所有较低级别节点的父节点。具有相同级别编号的下一个节点是其兄弟节点。

标签: javascript arrays object tree


【解决方案1】:

不需要递归。我认为您正在寻找这样的东西:

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);

【讨论】:

  • 谢谢你,本!正是我想要的。
【解决方案2】:

这是一个几乎没有意义(而且效率较低)的递归解决方案:

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);

(请注意,这依赖于解构赋值以跳过已处理的元素。您可以删除此功能,但会慢得多。)

我称这主要是没有意义的,因为它本质上是在尝试模仿迭代,以维护已经处理过的元素的计数,以便它可以在列表中向前跳过。我并不是说它完全没用,因为我仍然发现递归版本比迭代版本更容易阅读。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-06-22
    • 1970-01-01
    • 2020-09-29
    • 1970-01-01
    • 2020-11-10
    • 2015-10-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多