【问题标题】:build tree from json array in javascript with no parent key but a prefix从javascript中的json数组构建树,没有父键但有前缀
【发布时间】:2017-09-18 00:44:48
【问题描述】:

您将如何在没有父键或任何引用 id 但通过匹配 前缀 "- " 的 javascript 中从 json 数组构建树?

前缀在树的深度上递增。例如

"- " = level one
"- - " = level two
"- - - " = level three
...

有几个类似的问题,但尚未找到相关答案。

到目前为止,我已经做了如下的事情:

var $json = [
  { "id":"11", "text":"CatOne" },
  { "id":"12", "text":"- CatOneSubCat1" },
  { "id":"13", "text":"- CatOneSubCat2" },
  { "id":"14", "text":"- - CatOneSubCat2SubCat1" },
  { "id":"15", "text":"- - CatOneSubCat2SubCat2" },
  { "id":"16", "text":"- CatOneSubCat3" },
  { "id":"17", "text":"CatTwo" },
  { "id":"18", "text":"CatThree" },
  { "id":"19", "text":"CatFour" },
  { "id":"20", "text":"- CatFourSubCat1" },
  { "id":"21", "text":"- CatFourSubCat2" },
  { "id":"22", "text":"CatFive" }
];

$(document).ready(function(){
  var $arr = [];
  var $str = "";
  var $prefix = "- "; 

  $.each( $json, function( key, value ) {
    value.children = [];
    // TODO: additional prefix should be appended upon the depth of tree
    if(!value.text.startsWith($prefix)) {
    	$arr.push(value);
    }
    else {
    	$arr[$arr.length - 1].children.push(value);
    }
  });
  $("#mypre").text(JSON.stringify($arr, null, 2));
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<pre id="mypre"></pre>

上面sn-p的结果:

[
    { "id":"11", "text":"CatOne", "children":[
        { "id":"12", "text":"- CatOneSubCat1", "children":[] },
        { "id":"13", "text":"- CatOneSubCat2", "children":[] },
        { "id":"14", "text":"- - CatOneSubCat2SubCat1", "children":[] },
        { "id":"15", "text":"- - CatOneSubCat2SubCat2", "children":[] },
        { "id":"16", "text":"- CatOneSubCat3", "children":[] }
    ] },
    { "id":"17", "text":"CatTwo", "children":[] },
    { "id":"18", "text":"CatThree", "children":[] },
    { "id":"19", "text":"CatFour", "children":[
        {"id":"20", "text":"- CatFourSubCat1", "children":[] },
        {"id":"21", "text":"- CatFourSubCat2", "children":[] }
    ] },
    { "id":"22", "text":"CatFive", "children":[] }
]

预期结果:

[
    { "id":"11", "text":"CatOne", "children":[
        { "id":"12", "text":"- CatOneSubCat1", "children":[] },
        { "id":"13", "text":"- CatOneSubCat2", "children":[
            { "id":"14", "text":"- - CatOneSubCat2SubCat1", "children":[] },
            { "id":"15", "text":"- - CatOneSubCat2SubCat2", "children":[] }
        ]},
        { "id":"16", "text":"- CatOneSubCat3", "children":[] }
    ] },
    { "id":"17", "text":"CatTwo", "children":[] },
    { "id":"18", "text":"CatThree", "children":[] },
    { "id":"19", "text":"CatFour", "children":[
        { "id":"20", "text":"- CatFourSubCat1", "children":[] },
        { "id":"21", "text":"- CatFourSubCat2", "children":[] },
    ] },
    { "id":"22", "text":"CatFive", "children":[] }
]

【问题讨论】:

  • 没有像 JSON 数组 这样的东西。 JSON总是是一个字符串。

标签: javascript jquery arrays json recursion


【解决方案1】:

这是使用递归的一种方法。

我特别喜欢这个答案,因为在 aux 主循环中几乎没有精神开销。因为我们正在构建一棵树,所以我们的流程分支为循环的多次迭代以构建最终结果是有意义的。

  • 如果当前节点 x 曾经是 undefined 或节点深度级别降低,我们就完成了对这个深度的迭代
  • 如果节点深度级别保持不变,则找到下一个深度级别的所有节点,当前深度继续迭代级别
  • 否则节点深度级别会增加,我们将跳过当前深度的那个节点

除了我添加的小 depth 辅助函数(也是递归的)之外,没有别的了。

// type Node = Node { id :: String, text :: String, nodes :: [Node] }

// depth :: Node -> Int
const depth = ({ text: [x, y, ...text] }) =>
  (x + y === '- ') ? 1 + depth({ text }) : 0

// buildTree :: [Node] -> [Node]
const buildTree = xs => {
  const aux = (d, [x,...xs]) => {
    if (x === undefined || depth(x) < d)
      return []
    else if (depth(x) === d)
      return [Object.assign({}, x, {nodes: aux(d+1, xs)}), ...aux(d, xs)]
    else
      return aux(d, xs) 
  }
  return aux(0, xs)
}

const nodes = [
  { id: '11', text: 'CatOne' },
  { id: '12', text: '- CatOneSubCat1' },
  { id: '13', text: '- CatOneSubCat2' },
  { id: '14', text: '- - CatOneSubCat2SubCat1' },
  { id: '15', text: '- - CatOneSubCat2SubCat2' },
  { id: '16', text: '- CatOneSubCat3' },
  { id: '17', text: 'CatTwo' },
  { id: '18', text: 'CatThree' },
  { id: '19', text: 'CatFour' },
  { id: '20', text: '- CatFourSubCat1' },
  { id: '21', text: '- CatFourSubCat2' },
  { id: '22', text: 'CatFive' }
]

const tree = buildTree(nodes)

console.log(JSON.stringify(tree, null, '  '))

【讨论】:

    【解决方案2】:

    您可以使用数组作为最后插入的关卡对象的引用,并在检查关卡时迭代给定的数组。

    var data = [{ id: "11", text: "CatOne" }, { id: "12", text: "- CatOneSubCat1" }, { id: "13", text: "- CatOneSubCat2" }, { id: "14", text: "- - CatOneSubCat2SubCat1" }, { id: "15", text: "- - CatOneSubCat2SubCat2" }, { id: "15a", text: "- - -     extra space" }, { id: "16", text: "- CatOneSubCat3" }, { id: "17", text: "CatTwo" }, { id: "18", text: "CatThree" }, { id: "19", text: "CatFour" }, { id: "20", text: "- CatFourSubCat1" }, { id: "21", text: "- CatFourSubCat2" }, { id: "22", text: "CatFive" }],
        tree = function (array) {
            var levels = [{}];
            data.forEach(function (a) {
                var level = Math.floor(a.text.match(/^(- )*/)[0].length / 2);
                levels.length = level + 1;
                levels[level].children = levels[level].children || [];
                levels[level].children.push(a);
                levels[level + 1] = a;
            });
            return levels[0].children;
        }(data);
      
    console.log(tree);
    .as-console-wrapper { max-height: 100% !important; top: 0; }

    【讨论】:

    • Math.floor("- - - SS".match(/^([ \-]*)+/)[0].length/2) 返回 4 而不是 3,其中S = "extra space"
    • 额外空间是什么意思?
    • SO 去掉多余的空格,所以S 被用作占位符,请看这个小提琴jsfiddle.net/rw25p8hh
    • 我现在有一个带有额外空间的对象,{ id: "15a", text: "- - - extra space" } 现在应该可以使用更改后的正则表达式。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-03-07
    • 2019-12-24
    • 1970-01-01
    • 2021-04-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多