Darren Wainwright
Darren Wainwright

Reputation: 30757

Javascript Recursion on array and child arrays

Having a senior-moment, and struggling to get a recursive method to work correctly in Javascript.

There are similar Q&A's here, though nothing I see that has helped me so far.

That being said, if there is indeed a duplicate, i will remove this question.

Given the following array of objects:

var collection = [
                    {
                        id: 1,
                        name: "Parent 1",
                        children: [
                            { id: 11, name: "Child 1", children: [] },
                            { id: 12, name: "Child 2", children: [] }
                        ]
                    },
                    {
                        id: 2,
                        name: "Parent 2",
                        children: [
                            {
                                id: 20,
                                name: "Child 1",
                                children: [
                                    { id: 21, name: "Grand Child 1", children: [] },
                                    { id: 22, name: "Grand Child 2", children: [] }
                                ]
                            }
                        ]
                    },
                    {
                        id: 3,
                        name: "Parent 3",
                        children: [
                            { id: 31, name: "Child 1", children: [] },
                            { id: 32, name: "Child 2", children: [] }
                        ]
                    },
                ];

I've gone through a few attempts though my method seems to return early after going through one level only.

My latest attempt is:

Can someone please point me in the right direction.

function findType(col, id) {


                    for (i = 0; i < col.length; i++) {

                        if (col[i].id == id) {
                            return col[i];

                        }

                        if (col[i].children.length > 0) {
                           return findType(col[i].children, id);

                        }
                    }

                    return null;

                }

I am trying to find an object where a given id matches, so looking for id 1 should return the whole object with the name Parent 1. If looking for id 31 then the whole object with the id 31 and name Child 1 should be returned.

This would translate into

var t = findType(collection, 1);

or

var t = findType(collection, 31);

Note I would like help with a pure JavaScript solution, and not a plugin or other library. Though they may be more stable, it won't help with the learning curve. Thanks.

Upvotes: 5

Views: 3683

Answers (4)

Nina Scholz
Nina Scholz

Reputation: 386883

You was close, you need a variable to store the temporary result of the nested call of find and if found, then break the loop by returning the found object.

Without, you return on any found children without iterating to the end of the array if not found at the first time.

function findType(col, id) {
    var i, temp;
    for (i = 0; i < col.length; i++) {
        if (col[i].id == id) {
            return col[i];
        }
        if (col[i].children.length > 0) {
            temp = findType(col[i].children, id); // store result
            if (temp) {                           // check
                return temp;                      // return result
            }
        }
    }
    return null;
}

var collection = [{ id: 1, name: "Parent 1", children: [{ id: 11, name: "Child 1", children: [] }, { id: 12, name: "Child 2", children: [] }] }, { id: 2, name: "Parent 2", children: [{ id: 20, name: "Child 1", children: [{ id: 21, name: "Grand Child 1", children: [] }, { id: 22, name: "Grand Child 2", children: [] }] }] }, { id: 3, name: "Parent 3", children: [{ id: 31, name: "Child 1", children: [] }, { id: 32, name: "Child 2", children: [] }] }];

console.log(findType(collection, 31));
console.log(findType(collection, 1));
.as-console-wrapper { max-height: 100% !important; top: 0; }

Upvotes: 3

user7364588
user7364588

Reputation: 1154

1. Actually your function findType return the value null for every id parameter at the node

{ id: 11, name: "Child 1", children: [] }

When you hit return, it stops all the recursion.

You have to check the return value from the nested call of findType function.


2. Your for loop should looke like
for (let i = 0; i < col.length; i++)
instead of
for (i = 0; i < col.length; i++)
Because without the let you share a same variable i in the nested call of the function findType and the value will be changed for the dad calling function.


The function could be :

function findType(col, id) {
    for (let i = 0; i < col.length; i++) {

     if (col[i].id == id) {
      return col[i];
     }

     var nested = findType(col[i].children, id);

     if (nested) return nested;
   }

   return null;
 }   

Upvotes: 1

Ele
Ele

Reputation: 33736

You need to ask for the "found" object

let found = findType(col[i].children, id);
if (found) {
    return found;
}

Look at this code snippet

var collection = [{    id: 1,    name: "Parent 1",    children: [{        id: 11,        name: "Child 1",        children: []      },      {        id: 12,        name: "Child 2",        children: []      }    ]  },  {    id: 2,    name: "Parent 2",    children: [{      id: 20,      name: "Child 1",      children: [{          id: 21,          name: "Grand Child 1",          children: []        },        {          id: 22,          name: "Grand Child 2",          children: []        }      ]    }]  },  {    id: 3,    name: "Parent 3",    children: [{        id: 31,        name: "Child 1",        children: []      },      {        id: 32,        name: "Child 2",        children: []      }    ]  }];

function findType(col, id) {
  for (let i = 0; i < col.length; i++) {
    if (col[i].id == id) {
      return col[i];
    }

    if (col[i].children.length > 0) {
      let found = findType(col[i].children, id);
      if (found) {
        return found;
      }
    }
  }
  
  return null;
}


var t = findType(collection, 31);
console.log(t);
.as-console-wrapper {
  max-height: 100% !important
}

Upvotes: 1

Semi-Friends
Semi-Friends

Reputation: 480

const findType = (ar, id) => {
  return ar.find(item => {
    if (item.id === id) {
       return item;
    }

    return item.children.find(cItem => cItem.id === id)
  })
}

I think this suffice your needs

Upvotes: 1

Related Questions