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

时间:2011-07-05 03:13:17

标签: javascript algorithm data-structures tree

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

不幸的是,这需要能够通过引用传递,这是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,并且为了练习的目的可以完全不同地格式化。

非常感谢任何输入!

2 个答案:

答案 0 :(得分:2)

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

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 :(得分:1)

想法#1

这是你可能没想到的答案。

看看你期望的输出,我想知道是否最简单的方法就是生成JSON然后在你完成后再评估它。根本没有参考。

在浏览平面阵列时,您基本上有三个操作:

  1. 您向当前对象添加更多数据
  2. 关闭当前对象
  3. 您创建一个新的子对象
  4. 通过将正确的文本附加到正在构建的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设计模式是传入数组并返回一个修改过的数组,取而代之整个原始数组,包含返回的修改后的数组。