将对象列表转换为JavaScript树形结构

4
我希望将一个对象列表转换成可被jstree解析的json格式。
data = [
    { 
        "data" : { 
            "title" : "father",
            "attr" : { "href" : "#" }
        },
        "children" : [
            { 
                "data" : { 
                    "title" : "Older Son",
                    "attr" : { "href" : "#" }
                },
                "children" : []
            },
            { 
                "data" : { 
                    "title" : "Younger Son",
                    "attr" : { "href" : "#" }
                },
                "children" : []
            }
        ]
    },
]

我的输入看起来像这样:

[
Object
id: 35
name: "bnm,bnm"
parent_id: null
, 
Object
id: 36
name: "ghk"
parent_id: 35
, 
Object
id: 37
name: "hgkgh"
parent_id: null
, 
Object
id: 38
name: "jklhjk"
parent_id: null
, 
Object
id: 39
name: "fghdfgh"
parent_id: 38
, 
Object
id: 40
name: "bsdbd"
parent_id: 38
,
...]

说实话,这不是一棵树,而是一片森林。但这并不重要。

我已经花了很多时间,但没有成功地让它工作。在JavaScript中操作数组似乎比Java、C++或PHP更麻烦...

到目前为止,我尝试的方法是:

  1. (前置)源数据(对象列表)符合一个条件:儿子不能出现在父亲之前
  2. 将其转换为关联数组(键=id,值=对象),因此必须使用字符串作为键。
  3. 弹出最后一个数组元素,并将其推入其父元素的子元素数组中。对于所有非空父元素重复此过程。
  4. 希望这样做应该可以解决问题。

请发布一下你已经尝试过的内容。这样可能会更容易帮助我们为您提供帮助。 - Felix Kling
我觉得PHP数组比JavaScript数组更糟糕。JS非常简洁。你想要做什么,哪里没成功,我不太明白... - elclanrs
我已经编辑了我的帖子并描述了算法的想法。我知道我应该在stackoverflow上写下我到目前为止尝试过的内容,但我对JS不熟悉,我的代码看起来很丑陋,可能没有意义粘贴在这里 :/... - ducin
2个回答

9

首先,您需要将所有项目放入由它们的ID索引的稀疏数组中,并翻译除子项(应该存在但为空)以及包括父级ID在内的所有内容:

var itemsByID = [];
items.forEach(function(item) {
    itemsByID[item.id] = {
        data: {title: item.name},
        children: [],
        parentID: item.parent_id
    };
});

接下来您需要遍历所有的项目,并将子项添加到它们的父级:

itemsByID.forEach(function(item) {
    if(item.parentID !== null) {
        itemsByID[item.parentID].children.push(item);
    }
});

然后找到根:

var roots = itemsByID.filter(function(item) { return item.parentID === null; });

然后通过删除父ID来清理项目:

itemsByID.forEach(function(item) { delete item.parentID; });

树的根将在roots中。


你的方法没有成功的原因是,如果任何子元素具有大于其父元素的ID编号,则父元素将不存在;您已经处理并弹出了它。必须在完成之前保留数组中的所有项。


为了简单起见,我使用了一些在旧版浏览器中可能不可用的数组方法。这些方法可以安全地进行 shim 或修改代码以避免使用这些方法。 - icktoofay
好的,我尝试了你的算法,但是我不喜欢JS在数组中的“空洞”中插入undefined(实际上,我想要一个典型的映射结构在中间阶段)。所以我决定创建一个字符串键入的数组。 - ducin
@tkoomzaaskz:这不是特定于数组的。在对象上访问不存在的属性会产生“undefined”。此外,所有对象(包括数组)的属性都是字符串键控的;只是数组的属性是数字的字符串表示形式。(当您使用整数“b”执行a[b]时,它被强制转换为字符串。) - icktoofay
也许是我的Chrome JavaScript控制台让我认为数组与实际不同(这让我认为它用undefined填充空洞)。无论如何,非常感谢! - ducin
@tkoomzaaskz:它确实有点这个意思;孔不一定在内存中表示,但它们可以。这无关紧要,因为如果明确设置为“未定义”,它将是“未定义”,如果没有明确定义,则将被设置为“未定义”。 - icktoofay

1
也许 unsplay 可以解决问题?
>> var unsplay = require('unsplay');
>> unsplay([{id: 0}, {id: 1, pid: 0}], 'id', 'pid');
[{
  item: {id: 0},
  children: [{
    item: {id: 1, pid: 0},
    children: []
  }]
}]

(免责声明:本人为作者)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接