在JavaScript中从平面数组生成树结构(不使用对象引用)

Generating Tree Structure from Flat Array in JavaScript (without using object references)

本文关键字:对象引用 结构 生成树 JavaScript 平面 数组      更新时间:2023-09-26

我正试图用JavaScript从一个平面数组生成一个树结构。这通常是一个相当简单的命题-只需保留一个"堆栈"数组,其中引用了按嵌套深度排序的当前工作范围的祖先对象-在进入另一个嵌套级别时将一个新元素推到堆栈上,在离开一个嵌套级时将其弹出,用(新的(最后一个数组项引用的对象替换当前工作元素。

不幸的是,这需要通过引用传递的能力,而JavaScript没有这种能力(好吧,我不知道如何使用来解决这个问题。(

为了提供一些背景知识,我试图将一个包含嵌套XML样式(但不是XML,因此不能使用XML解析器(令牌的任意长/复杂字符串转换为类似于下面的结构:

预期输入:

[
    "<token>",
    "<my non compliant token>",
    "some text at this level",
    "<some other token>",
    "some more text",
    "<yet another token>",
    "more text",
    "</yet another token>",
    "blah!",
    "</some other token>",
    "</token>",
    "more text"
]

预期输出

[
    {
        "token": "<token>",
        "children": [
            {
                "token": "<my non compliant token>",
                "children": [
                    "some text at this level",
                    {
                        "token": "<some other token>",
                        "children": [
                            "some more text",
                            {
                                "token": "<yet another token>",
                                "children": [ "more text" ]
                            },
                            "blah!"
                        ]
                    }
                ]
            }
        ]
    },
    "more text"
]

为了澄清——我不是在追求整个算法(但如果你想提供你的实现,我会感兴趣(——只是一个在输出树中保持当前位置的好方法(或者一种完全不同/更好的生成树对象的方法!(不要太在意令牌是如何工作的——它们不是XML,为了练习的目的,可以完全格式化不同地

如有任何意见,我们将不胜感激!

您的字符串看起来很容易解析。我想我会这样做:

var stack = [];
var array = [];
for (var i in strings) {
   var s = strings[i];
   if (s.indexOf("</") == 0) {
      array = stack.pop();
   } else if (s.indexOf("<") == 0) {
      var obj = {token: s, children: []};
      array.push(obj);
      stack.push(array);
      array = obj.children;
   } else {
      array.push(s);
   }
}

创意#1

这是一个你可能没有预料到的答案。

看看您的预期输出,我想知道生成JSON并在完成后对其进行评估是否最简单。根本没有参考资料。

当浏览你的平面阵列时,你基本上有三个操作:

  1. 将更多数据添加到当前对象
  2. 关闭当前对象
  3. 创建新的子对象

只需将适当的文本附加到您正在构建的JSON字符串上,就可以非常容易地完成这三项工作,因为您在迭代源数组时只需生成您在预期输出中显示的文本。完成后,通过eval运行该JSON字符串。如果输入中存在错误,您可能需要进行一些安全检查来验证每个数组和对象是否正确关闭,但它应该可以正常工作。

想法#2

您仍然可以使用堆栈数组。我不知道为什么你需要通过引用传递,但你可以把一个索引传递到数组中,让每个人都通过索引修改数组的主副本。使用本地函数,主数组可以是一个公共数据值,它是主函数的本地值,但本质上是所有子函数的全局值,因此它们可以共享对它的访问。

这看起来像这样:

function ParseRawData(rawData)
{
    var parentScopeArray = [];   // main parent scope of objects
    function processTag(x)
    {
        // you can access parentScopeArray directly here and
        // and be accessing it by reference
    }
    // other code or local functions here
}

想法#3

如果您想将数组传递到一个函数中并修改主副本(也许是您考虑通过引用传递的原因(,javascript设计模式是将数组传递进来并返回一个修改后的数组,用返回的修改过的数组替换整个原始数组。