3

Is there a way to recurse the following JSON without for-looping the nested children?

My recursive function must be missing a case as it's not returning everything.

iterateTree(node, children) {
    console.log(node.name)

    if(node.children.length == 0) {
      return;
    }

    for(var i = 0; i < children.length; i++) {
      var child_node = children[i];

      return this.iterateTree(child_node, child_node.children);
    }
  }

for(var i = 0; i < sample.length; i++) {
      var node = sample[i];
      this.iterateTree(node, node.children);
    }

var sample = [
  {
    "name": "hello world",
    "children": [
      {
        "name": "fruits",
        "children": []
      },
      {
        "name": "vegetables",
        "children": []
      },
      {
        "name": "meats",
        "children": [
          {
            "name": "pork",
            "children": []
          },
          {
            "name": "beef",
            "children": []
          },
          {
            "name": "chicken",
            "children": [
              {
                "name": "organic",
                "children": []
              },
              {
                "name": "farm raised",
                "children": []
              }
            ]
          },
        ]
      }
    ]
  },
  {
    "name": "second folder",
    "children": []
  },
  {
    "name": "third folder",
    "children": [
      {
        "name": "breads",
        "children": []
      },
      {
        "name": "coffee",
        "children": [
          {
            "name": "latte",
            "children": []
          },
          {
            "name": "cappucino",
            "children": []
          },
          {
            "name": "mocha",
            "children": []
          },
        ]
      },
    ]
  }
]

Aiming to achieve the following output (similiar to file structure)

hello world
-fruits
-vegetables
-meats 
--pork
--beef
--chicken
---organic
---farm raised
second folder
third folder
-breads
-coffee
--latte
--cappucino
--mocha
1
  • Can you provide a snippet for verification? Commented May 9, 2019 at 11:00

3 Answers 3

4

You could create recursive function using reduce method to iterate through your nested data structure, return array and then use join method on that array.

var sample = [{"name":"hello world","children":[{"name":"fruits","children":[]},{"name":"vegetables","children":[]},{"name":"meats","children":[{"name":"pork","children":[]},{"name":"beef","children":[]},{"name":"chicken","children":[{"name":"organic","children":[]},{"name":"farm raised","children":[]}]}]}]},{"name":"second folder","children":[]},{"name":"third folder","children":[{"name":"breads","children":[]},{"name":"coffee","children":[{"name":"latte","children":[]},{"name":"cappucino","children":[]},{"name":"mocha","children":[]}]}]}]

function tree(data, prev = '') {
  return data.reduce((r, e) => {
    r.push(prev + e.name)
    if (e.children.length) r.push(...tree(e.children, prev + '-'));
    return r;
  }, [])
}

const result = tree(sample).join('\n')
console.log(result)

To create same structure in HTML you could use forEach method instead.

var sample = [{"name":"hello world","children":[{"name":"fruits","children":[]},{"name":"vegetables","children":[]},{"name":"meats","children":[{"name":"pork","children":[]},{"name":"beef","children":[]},{"name":"chicken","children":[{"name":"organic","children":[]},{"name":"farm raised","children":[]}]}]}]},{"name":"second folder","children":[]},{"name":"third folder","children":[{"name":"breads","children":[]},{"name":"coffee","children":[{"name":"latte","children":[]},{"name":"cappucino","children":[]},{"name":"mocha","children":[]}]}]}]

function tree(data, parent) {
  const ul = document.createElement('ul');
  data.forEach(el => {
    const li = document.createElement('li');
    li.textContent = el.name;
    ul.appendChild(li);
    if (el.children.length) {
      tree(el.children, li)
    }
  })
  parent.appendChild(ul)
}

const parent = document.getElementById('root')
tree(sample, parent)
<div id="root"></div>

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks this is an impressive function. However what if you wanted to output nested <ul><li></li></ul> combination instead of purely text dash (-).
0

var sample = [{"name":"hello world","children":[{"name":"fruits","children":[]},{"name":"vegetables","children":[]},{"name":"meats","children":[{"name":"pork","children":[]},{"name":"beef","children":[]},{"name":"chicken","children":[{"name":"organic","children":[]},{"name":"farm raised","children":[]}]}]}]},{"name":"second folder","children":[]},{"name":"third folder","children":[{"name":"breads","children":[]},{"name":"coffee","children":[{"name":"latte","children":[]},{"name":"cappucino","children":[]},{"name":"mocha","children":[]}]}]}]

  level = 0;
  var hyphens = '';

  function recursive_loop(s) {  
    console.log(hyphens + s.name);
    var c = s.children;
    if (c.length) hyphens += '-';
    var empty = false;
    for (let i = 0; i < c.length; i++) {
      if (c[i].children) {
        recursive_loop(c[i]);
      }
      if (c[i].children.length)
        empty = true;
    }
    if (empty) hyphens = '';
  }
  for (let i = 0; i < sample.length; i++) {
    recursive_loop(sample[i]);
  }

Comments

0

We use object-scan foe many data processing / traversal tasks. It's powerful once you wrap your head around it. Here is how you could solve your question

// const objectScan = require('object-scan');

const display = (input) => objectScan(['**'], {
  reverse: false,
  rtn: 'entry',
  filterFn: ({ value }) => typeof value === 'string'
})(input)
  .map(([k, v]) => `${'-'.repeat(k.length / 2 - 1)}${v}`);

const sample = [{ name: 'hello world', children: [{ name: 'fruits', children: [] }, { name: 'vegetables', children: [] }, { name: 'meats', children: [{ name: 'pork', children: [] }, { name: 'beef', children: [] }, { name: 'chicken', children: [{ name: 'organic', children: [] }, { name: 'farm raised', children: [] }] }] }] }, { name: 'second folder', children: [] }, { name: 'third folder', children: [{ name: 'breads', children: [] }, { name: 'coffee', children: [{ name: 'latte', children: [] }, { name: 'cappucino', children: [] }, { name: 'mocha', children: [] }] }] }];

const result = display(sample);
result.forEach((l) => console.log(l));
// => hello world
// => -fruits
// => -vegetables
// => -meats
// => --pork
// => --beef
// => --chicken
// => ---organic
// => ---farm raised
// => second folder
// => third folder
// => -breads
// => -coffee
// => --latte
// => --cappucino
// => --mocha
.as-console-wrapper {max-height: 100% !important; top: 0}
<script src="https://bundle.run/[email protected]"></script>

Disclaimer: I'm the author of object-scan

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.