Рекурсивная функция не выполняется - PullRequest
0 голосов
/ 04 сентября 2018

Я пытаюсь рекурсивно загрузить структуру графа сцены из файла JSON. Моя идея состояла в том, чтобы вызывать одну и ту же функцию на всех дочерних узлах, пока у последнего узла не будет дочерних узлов. Однако при отладке кода я обнаружил, что рекурсивный вызов loadNodes во втором цикле игнорируется, и вместо этого цикл просто увеличивает счетчик и начинается со следующего цикла.

Я проверил свой синтаксис и проверю вызов других функций внутри цикла (что работает) ..

Кто-нибудь имеет представление о том, что я делаю неправильно?

function loadNodes(obj, current_group_node) {
    for (let i = 0; i < obj.length; i++) {
        if (obj[i].nodetype === 'group') {
            let new_group_node = new GroupNode(new Matrix(obj[i].matrix));
            current_group_node.add(new_group_node);
            for (let j = 0; j < obj[i].children.length; j++) {
                loadNodes(obj[i].children[j], new_group_node);
            }
        } else {
           // some more logic

        }
    }
}

Моя функция получает массив объектов со следующей возможной структурой:

{
  "nodetype": "group",
  "name": "root",
  "matrix": [
    1,0,0,0,
    0,1,0,0,
    0,0,1,0,
    0,0,0,1
  ],
  "children": [
    {
      "nodetype": "group",
      "name": "driver-cube-group",
      "matrix": [
        1,0,0,0,
        0,1,0,0,
        0,0,1,0,
        0,0,0,1
      ],
      "children": [
        {
          "nodetype": "aabox",
          "name": "driver-cube",
          "minpoint": {
            "x": -3,
            "y": -3,
            "z": -3,
            "w": 1
          },
          "maxpoint": {
            "x": -2,
            "y": -2,
            "z": -2,
            "w": 1
          },
          "color": {
            "x": 1,
            "y": 1,
            "z": 1,
            "w": 1
          }
        }
      ]
    }
  ]
}

Ответы [ 2 ]

0 голосов
/ 04 сентября 2018

При условии, что JSON передается вашей функции в том виде, в каком вы ее опубликовали , я пришел к следующему решению (я изменил некоторые из номенклатуры, а также заменил два экземпляра, создав объект и присвоив ему массив к нему для вложенных объектов):

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
      xml:lang="en">
<head>
<title>JSON Test Case</title>
<script type="application/javascript">
/* <![CDATA[ */
'use strict';

var nested = 0;

function loadNodes(p_obj, p_current_group_node)
  {
let l_i;
let l_new_group_node;

  nested++;

  console.log('Entering loadNodes (' + nested + ')...');
  console.log('Length of object: ' + p_obj.length);     // Oops...!
  console.log('Type of JSON object: ' + typeof p_obj);
  console.log('Determining the node type: ' + p_obj.nodetype);
  console.log('Node name: ' + p_obj.name);
  if(p_obj.nodetype == 'group')
    {
    console.log('Number of elements: ' + p_obj.children.length);

    for(l_i = 0; l_i < p_obj.children.length; l_i++)
      {
      console.log('Found a subtree for processing!');

      l_new_group_node = new Object();
      l_new_group_node.nodes = new Array();
      p_current_group_node.nodes.push(l_new_group_node);
      loadNodes(p_obj.children[l_i], l_new_group_node);
      }
    }
  else
    console.log('Process leaf node here...');

  console.log('Leaving loadNodes (' + nested + ')...');
  nested--;
  }
/* ]]> */
</script>
</head>
<body>
<header><h1>JSON test case</h1></header>
<main>
<script type="application/javascript">
/* <![CDATA[ */
var json = {
  "nodetype": "group",
  "name": "root",
  "matrix": [
    1,0,0,0,
    0,1,0,0,
    0,0,1,0,
    0,0,0,1
  ],
  "children": [
    {
      "nodetype": "group",
      "name": "driver-cube-group",
      "matrix": [
        1,0,0,0,
        0,1,0,0,
        0,0,1,0,
        0,0,0,1
      ],
      "children": [
        {
          "nodetype": "aabox",
          "name": "driver-cube",
          "minpoint": {
            "x": -3,
            "y": -3,
            "z": -3,
            "w": 1
          },
          "maxpoint": {
            "x": -2,
            "y": -2,
            "z": -2,
            "w": 1
          },
          "color": {
            "x": 1,
            "y": 1,
            "z": 1,
            "w": 1
          }
        }
      ]
    }
  ]
}
var myobj = new Object();
myobj.nodes = new Array();

loadNodes(json, myobj);
/* ]]> */
</script>
</main>
</body>
</html>

Прежде всего, я мог бы выбросить внешний цикл, потому что он даже не запускается и поэтому предотвращает рекурсию (я обнаружил, что p_obj.length даже возвращает undefined, если вы пытаетесь получить доступ к этому свойству) , В конце концов, это объект, и это, очевидно, не обеспечивает длину. Вместо этого я проверяю параметры объекта, который мы получили, и затем определяю, нужно ли нам спускаться дальше или мы достигли конечного узла.

Если нам нужно спуститься дальше, то в действительности существует цикл, который копает массив, присвоенный свойству children - который на самом деле имеет длину, поэтому мы можем принять его для нашего условия завершения.

Если вы хотите увидеть, что на самом деле происходит, вы можете запустить этот тестовый пример с открытой консолью вашего браузера. Я вставил различные заявления, в которых записана конкретная информация, чтобы вы могли видеть, что здесь делается.
Также следует обратить внимание на записи Ввод loadNodes (...) и Выход из loadNodes (...) , потому что они сообщают вам, где на самом деле происходит рекурсия и когда рекурсивно Вызванная функция оставлена. Вы можете найти уровень вложенности в скобках.

0 голосов
/ 04 сентября 2018

loadNodes ожидает, что первый аргумент будет массивом объектов, а не единственным объектом. Вам не нужно вызывать его в цикле для каждого дочернего объекта, просто вызовите его один раз, передав массив child в качестве аргумента. Он выполняет свой цикл по массиву.

Так замените это:

        for (let j = 0; j < obj[i].children.length; j++) {
            loadNodes(obj[i].children[j], new_group_node);
        }

с:

        loadNodes(obj[i].children, new_group_node);

Может быть полезно переименовать первый аргумент с obj на arr, чтобы было ясно, что он ожидает массив, а не один объект.

...