1

I'm trying to learn recursion and I have a code that tries to extract all parent names and push them to array if they have children.

My problem is that I am able to print out all the parents but can only seem to push 2 out of 5 of them.

function printChildrenRecursive(t) {
  let hasChildren = []

  if (t.children.length === 0) {
    return
  }

  t.children.forEach(child => {
    if (child.children.length > 0) {
      console.log(child.name)
      hasChildren.push(child.name)
    }
    printChildrenRecursive(child)
  })

  return hasChildren
}

const tree = {
  name: 'John',
  children: [{
      name: 'Jim',
      children: [{
        name: 'Joe',
        children: [{
          name: 'Lee',
          children: []
        }]
      }]
    },
    {
      name: 'Zoe',
      children: [{
          name: 'Kyle',
          children: [{
            name: 'Tony',
            children: []
          }]
        },
        {
          name: 'Sophia',
          children: [{
            name: 'Thor',
            children: []
          }]
        }
      ]
    }
  ]
}

let res = printChildrenRecursive(tree)
console.log(res);

The console.log outputs

Jim
Joe
Zoe
Kyle
Sophia

But the hasChildren.push only outputs

(2) ["Jim", "Zoe"]
2
  • 1
    Is printChildrenRecursive is a strange name for a function that should return an array of parents. Commented Sep 26, 2020 at 10:56
  • I know, I was just following a tutorial about printing children but forgot about it as I tried to tinker with the code. Commented Sep 26, 2020 at 13:58

2 Answers 2

3

There are two places where you do not deal well with the array that should be returned:

  1. In the base case, don't just return, but do return []

  2. In the recursive case, don't ignore the value that is returned from the recursive call, but append it to your current array.

Here is the correction:

function printChildrenRecursive(t) {
  let hasChildren = [];
  if (t.children.length === 0) {
    return []; // always return an array!
  }
  t.children.forEach(child => {
    if (child.children.length > 0) {
      console.log(child.name);
      hasChildren.push(child.name);
    }
    // add the returned array: 
    hasChildren.push(...printChildrenRecursive(child));
  })
  return hasChildren;
}

const tree = {name: 'John',children: [{name: 'Jim',children: [{name: 'Joe',children: [{name: 'Lee',children: []}]}]},{name: 'Zoe',children: [{name: 'Kyle',children: [{name: 'Tony',children: []}]},{name: 'Sophia',children: [{name: 'Thor',children: []}]}]}]};

let result = printChildrenRecursive(tree);
console.log(result);

Alternative solution

The algorithm does not return the root node, as it focuses on children -- possibly this is intended.

Also the order of output is a mix of breadth-first and depth-first. The more common order for recursion would be a depth-first order -- like preorder.

And why not use a generator.

Here is an implementation of that:

function *dfs(node) {
    // If you want to include leaves, remove the condition:
    if (node.children.length) yield node.name; 
    for (let child of node.children) yield *dfs(child);
}

const tree = {name: 'John',children: [{name: 'Jim',children: [{name: 'Joe',children: [{name: 'Lee',children: []}]}]},{name: 'Zoe',children: [{name: 'Kyle',children: [{name: 'Tony',children: []}]},{name: 'Sophia',children: [{name: 'Thor',children: []}]}]}]};

let result = Array.from(dfs(tree));
console.log(result);

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

2 Comments

What about John? It should be added too, no?
@Sergey, apparently it was not the intention of the Asker to get the root. Their function name hints to this.
1

Trincot already showed what was wrong with your implementation.

I would like to note that this can be written more simply. Here's a simple recursive function to collect the names of all the parent nodes:

const parents = ({name, children}) => 
  children .length > 0
    ? [name, ... children .flatMap (parents)]
    : []


const tree = {name: 'John', children: [{name: 'Jim', children: [{name: 'Joe', children: [{name: 'Lee', children: []}]}]}, {name: 'Zoe', children: [{name: 'Kyle', children: [{name: 'Tony', children: []}]}, {name: 'Sophia', children: [{name: 'Thor', children: []}]}]}]}

console .log (parents (tree))

If it's possible that some nodes will not have the children property, it's only slightly more complex:

const parents = ({name, children}) => 
  (children || []) .length > 0
    ? [name, ... children .flatMap (parents)]
    : []

If your requirement is to print them, then you can call this and print the results. I would suggest that you make it a habit to separate I/O from the core of your logic.

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.