4

So I have a multiple array of object and each object my contain a child.

e.g

const data = [
    {
        id: 1,
        name: 'parent 1',
        children: [
            {
                id: 'c1',
                name: 'child 1',
                children: [
                    {
                        id: 'g1',
                        name: 'grand 1',
                        children: [],
                    },
                ],
            },
        ],
    },
    {
        id: 2,
        name: 'parent 2',
        children: [
            {
                id: 2,
                name: 'c1',
                children: [],
            },
        ],
    },
    { id: 3, name: 'parent 3', children: [] },
];

what I wanted to happen is that if the Id that I'm searching for is 'g1', I would get the result

const result = ['parent 1', 'c1', 'grand 1']

the loop would only stop and get all the names that it went thru until the condition, in this case the id, is met

current approach done

/**
 * Details
 * @param id the value you are searching for
 * @param items nested array of object that has child
 * @param key name of the value you are looking for
 * @returns string of array that matches the id
 * @example ['parent 1', 'c1', 'grand 1']
 */
export function findAll(id: string, items: any, key: string): string[] {
  let i = 0;
  let found;
  let result = [];

  for (; i < items.length; i++) {
    if (items[i].id === id) {
      result.push(items[i][key]);
    } else if (_.isArray(items[i].children)) {
      found = findAll(id, items[i].children, key);
      if (found.length) {
        result = result.concat(found);
      }
    }
  }
  return result;
}

7
  • What have you tried? Also, const result = 'parent 1' > 'c1' > 'grand 1' this is invalid data object, you may verify what data structure do you want. Commented Aug 27, 2021 at 14:33
  • @ikhvjs, I updated the result that I wanted to see, thanks for the comment Commented Aug 27, 2021 at 14:35
  • What have you tried so far? I think a recursive function approach would be good for your case. Commented Aug 27, 2021 at 14:38
  • @ikhvjs, I tried this one, 3rd answer, stackoverflow.com/questions/30714938/… with some modifications but I can't seem to find a way to store the name of the parents on result array Commented Aug 27, 2021 at 14:45
  • Can you please show us your approach? Commented Aug 27, 2021 at 14:50

7 Answers 7

3

I wrote this iterative piece of code that may help you. It basically traverses the structure storing the path from the top-level until the desired id:

function getPath(obj, id) {
    // We need to store path
    // Start stack with root nodes
    let stack = obj.map(item => ({path: [item.name], currObj: item}));
    while (stack.length) {
        const {path, currObj} = stack.pop()
        if (currObj.id === id) {
            return path;
        } else if (currObj.children?.length) {
            stack = stack.concat(currObj.children.map(item => ({path: path.concat(item.name), currObj: item})));
        }
    }
    return null; // if id does not exists
}

This code assumes that your structure is correct and not missing any part (except for children that can be null). Btw, is your answer correct? I guess the path should be: ["parent 1", "child 1", "grand 1"]

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

Comments

1

The solution below is a recursive function that does the search.

const data = [
    {
        id: 1,
        name: 'parent 1',
        children: [
            {
                id: 'c1',
                name: 'child 1',
                children: [
                    {
                        id: 'g1',
                        name: 'grand 1',
                        children: [],
                    },
                ],
            },
        ],
    },
    {
        id: 2,
        name: 'parent 2',
        children: [
            {
                id: 2,
                name: 'c1',
            },
        ],
    },
    { id: 3, name: 'parent 3', children: [{}] },
];

function getPath(object, search) {
    if (object.id === search) return [object.name];
    else if ((object.children) || Array.isArray(object)) {
        let children = Array.isArray(object) ? object : object.children;
        for (let child of children) {
            let result = getPath(child, search);
            if (result) {
                if (object.id )result.unshift(object.name);
                return result;
            }
        }
    }
}

//const result = ['parent 1', 'c1', 'grand 1']
const result = getPath(data, 'g1');
console.log(result);

2 Comments

Hi Lajos, It is working fine when there is only one 'g1' in the data structure. What if the same 'g1' is present in the final child in another set of JSON. I dont have separate key called id in my data structure. I may have repeated data. Now How to pull the exact set of data that I want.?
@JohnsonAnthony my understanding about your problem is that you have a JSON which does not have an id and you might have duplicated results. If I understand your question correctly, then you want to find all matches. Is this an accurate understanding? Also, can you create a JSFiddle and share the link here in the comment section, or ask a separate question and share the link in the comment section? If you create it today, then I will probably look into it either today or tomorrow.
0

You can program a recursive function where you traverse your array at the time you accumulate the objects you traverse in a stack. Once you get an object with the id you want (id == g1) you print the solution. It could be something like this:

'use strict';

function print(stack) {
    //console.log("Printing result...\n");
    let result = "";
    stack.forEach(element => {
        result += element["name"] + " > ";
    });
    console.log(result + "\n");
}

function walkThrough(data, id, stack) {
    if (data !== undefined)
    for (let i = 0; i < data.length; i++) {
        const element = data[i];
        //console.log("Going through " + element["name"] + " with id == " + element["id"]);
        stack.push(element);
        if (element["id"] == id) print(stack);
        else walkThrough(element["children"], id, stack);            
    }
}

const data = [
    {
        "id": 1,
        "name": 'parent 1',
        "children": [
            {
                "id": 'c1',
                "name": 'child 1',
                "children": [
                    {
                        "id": 'g1',
                        "name": 'grand 1',
                        "children": [],
                    },
                ],
            },
        ],
    },
    {
        "id": 2,
        "name": 'parent 2',
        "children": [
            {
                "id": 2,
                "name": 'c1',
            },
        ],
    },
    { "id": 3, "name": 'parent 3', "children": [{}] },
];
//Calling the function to walk through the array...
walkThrough(data, 'g1', []);

Comments

0

Another aproach (not so elegant as above solutions, but it works also)

Very straight forward:
Iterating with for loop down to 3rd level, and when grandchild found in 3rd level, break to escape all 3 levels.

I am curious about how the different solutions would compare performance-wise for a large dataset (let's say a million records).

let i=0, k=0, l=0;

let childrenLength = 0, grandChildrenLength = 0;

let result = [];
let foundGrandChild = false;

function searchGrandChild(searchString) {

  for (i; i< data.length; ++i) {
    if(data.length > 0){
      childrenLength = data[i].children.length;

      if(childrenLength > 0) {
        for (k; k < childrenLength; ++k) {

          if(data[i].children[k] != undefined) {
            grandChildrenLength = data[i].children[k].children.length;

            if(grandChildrenLength > 0) {
              for (l; l < grandChildrenLength; ++l) {
                if(data[i].children[k].children[l] != undefined) {

                  if(data[i].children[k].children[l].id === searchString) {
                    result.push(data[i].name);
                    result.push(data[i].children[k].id);
                    result.push(data[i].children[k].children[l].name);
                    foundGrandChild = true;
                    console.log('Yap, we found your grandchild 😊')
                    console.log(result);
                    break;
                  }
                }
                if(foundGrandChild) break;
              }

            }
          }
          if(foundGrandChild) break;
        }

      }
    }
    if(foundGrandChild) break;
  }

  if(!foundGrandChild) console.log('sorry, we could not find your grandchild 😮')
};

const data = [
    {
        id: 1,
        name: 'parent 1',
        children: [
            {
                id: 'c1',
                name: 'child 1',
                children: [
                    {
                        id: 'g1',
                        name: 'grand 1',
                        children: [],
                    },
                ],
            },
        ],
    },
    {
        id: 2,
        name: 'parent 2',
        children: [
            {
                id: 2,
                name: 'c1',
            },
        ],
    },
    { id: 3, name: 'parent 3', children: [{}] },
];


console.log('Let us search for "g1" ...');
searchGrandChild('g1');

console.log('Let us now search for "g2" ...');
foundGrandChild = false;
searchGrandChild('g2');

Comments

0
const arr = [
  { id: "1234", parent_id: "", name: "jakson" },
  { id: "4567", parent_id: "1234", name: "obama" },
  { id: "7891", parent_id: "", name: "twinkel" },
  { id: "9876", parent_id: "1234", name: "behara" },
  { id: "1357", parent_id: "7891", name: "aaraku" },
  { id: "6789", parent_id: "7891", name: "mikel" },
  { id: "7892", parent_id: "4567", name: "aaraku" },
  { id: "8765", parent_id: "4567", name: "mikel" },
  { id: "9108", parent_id: "1234", name: "akshra" },
];
const generateChild = (arr) => {
  return arr.reduce((acc, val, ind, array) => {
    const childs = [];
    array.forEach((el) => {
      if (el.parent_id === val.id) {
        childs.push({ id: el.id, name: el.name, parent_id: el.parent_id });
      }
    });
    return acc.concat({ ...val, childs });
  }, []);
};
console.log(generateChild(arr));

output:
(9) [{...}, {...}, {...}, {...}, {...}, ...]
0
:
(4) {id: "1234", parent_id: "", name: "j...}
1
:
(4) {id: "4567", parent_id: "1234", name...}
2
:
(4) {id: "7891", parent_id: "", name: "t...}
3
:
(4) {id: "9876", parent_id: "1234", name...}
4
:
(4) {id: "1357", parent_id: "7891", name...}
5
:
(4) {id: "6789", parent_id: "7891", name...}
6
:
(4) {id: "7892", parent_id: "4567", name...}
7
:
(4) {id: "8765", parent_id: "4567", name...}
8`enter code here`
:
(4) {id: "9108", parent_id: "1234", name...}

1 Comment

Your answer could be improved with additional supporting information. Please edit to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers in the help center.
0
const arr = [
  { id: "1234", parent_id: "", name: "jakson" },
  { id: "4567", parent_id: "1234", name: "obama" },
  { id: "7891", parent_id: "", name: "twinkel" },
  { id: "9876", parent_id: "1234", name: "behara" },
  { id: "1357", parent_id: "7891", name: "aaraku" },
  { id: "6789", parent_id: "7891", name: "mikel" },
  { id: "7892", parent_id: "1234", name: "aaraku" },
  { id: "8765", parent_id: "1234", name: "aaraku" },
  { id: "9108", parent_id: "7891", name: "akshra" },
];

let data = [];
let test = [];
for (i = 0; i < arr.length; i++) {
  if (!test.includes(i)) {
    let x = arr[i];
    for (j = i + 1; j < arr.length; j++) {
      if (
        arr[j].name === arr[i].name &&
        arr[j].parent_id === arr[i].parent_id
      ) {
        Object.assign(x, arr[j]);
        test.push(j);
      }
    }
    data.push(x);
  }
}
console.log(data);
var parentChild = [];
for (i = 0; i < data.length; i++) {
  if (data[i].parent_id === "") {
    parentChild.push(data[i]);
  }
}

for (i = 0; i < data.length; i++) {
  for (j = 0; j < parentChild.length; j++) {
    if (data[i].parent_id === parentChild[j].id) {
      if (parentChild[j].child === undefined) {
        Object.assign(parentChild[j], {
          child: [],
        });
        parentChild[j].child.push(data[i]);
      } else {
        parentChild[j].child.push(data[i]);
      }
    }
  }
}
console.log(parentChild);

output:

(8) [{...}, {...}, {...}, {...}, {...}, ...]
0
:
(4) {id: "1234", parent_id: "", name: "j...}
id
:
"1234"
parent_id
:
""
name
:
"jakson"
child
:
(3) [{...}, {...}, {...}]
0
:
(3) {id: "4567", parent_id: "1234", name...}
id
:
"4567"
parent_id
:
"1234"
name
:
"obama"
1
:
(3) {id: "9876", parent_id: "1234", name...}
id
:
"9876"
parent_id
:
"1234"
name
:
"behara"
2
:
(3) {id: "8765", parent_id: "1234", name...}
id
:
"8765"
parent_id
:
"1234"
name
:
"aaraku"
1
:
(3) {id: "4567", parent_id: "1234", name...}
id
:
"4567"
parent_id
:
"1234"
name
:
"obama"
2
:
(4) {id: "7891", parent_id: "", name: "t...}
id
:
"7891"
parent_id
:
""
name
:
"twinkel"
child
:
(3) [{...}, {...}, {...}]
0
:
(3) {id: "1357", parent_id: "7891", name...}
id
:
"1357"
parent_id
:
"7891"
name
:
"aaraku"
1
:
(3) {id: "6789", parent_id: "7891", name...}
id
:
"6789"
parent_id
:
"7891"
name
:
"mikel"
2
:
(3) {id: "9108", parent_id: "7891", name...}
id
:
"9108"
parent_id
:
"7891"
name
:
"akshra"
3
:
(3) {id: "9876", parent_id: "1234", name...}
id
:
"9876"
parent_id
:
"1234"
name
:
"behara"
4
:
(3) {id: "1357", parent_id: "7891", name...}
id
:
"1357"
parent_id
:
"7891"
name
:
"aaraku"
5
:
(3) {id: "6789", parent_id: "7891", name...}
id
:
"6789"
parent_id
:
"7891"
name
:
"mikel"
6
:
(3) {id: "8765", parent_id: "1234", name...}
id
:
"8765"
parent_id
:
"1234"
name
:
"aaraku"
7
:
(3) {id: "9108", parent_id: "7891", name...}
id
:
"9108"
parent_id
:
"7891"
name
:
"akshra"
(2) [{...}, {...}]
0
:
(4) {id: "1234", parent_id: "", name: "j...}
id
:
"1234"
parent_id
:
""
name
:
"jakson"
child
:
(3) [{...}, {...}, {...}]
0
:
(3) {id: "4567", parent_id: "1234", name...}
id
:
"4567"
parent_id
:
"1234"
name
:
"obama"
1
:
(3) {id: "9876", parent_id: "1234", name...}
id
:
"9876"
parent_id
:
"1234"
name
:
"behara"
2
:
(3) {id: "8765", parent_id: "1234", name...}
id
:
"8765"
parent_id
:
"1234"
name
:
"aaraku"
1
:
(4) {id: "7891", parent_id: "", name: "t...}
id
:
"7891"
parent_id
:
""
name
:
"twinkel"
child
:
(3) [{...}, {...}, {...}]

1 Comment

Your answer could be improved with additional supporting information. Please edit to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers in the help center.
0
const arr = [
  { id: "1234", parent_id: "", name: "jakson" },
  { id: "4567", parent_id: "1234", name: "obama" },
  { id: "7891", parent_id: "", name: "twinkel" },
  { id: "9876", parent_id: "1234", name: "behara" },
  { id: "1357", parent_id: "7891", name: "aaraku" },
  { id: "6789", parent_id: "7891", name: "mikel" },
  { id: "7892", parent_id: `enter code here`"4567", name: "aaraku" },
  { id: "8765", parent_id: "4567", name: "mikel" },
  { id: "9108", parent_id: "1234", name: "akshra" },
];
const generateChild = (arr) => {
  return arr.reduce((acc, val, ind, array) => {
    const childs = [];
    array.forEach((el) => {
      if (el.parent_id === val.id) {
        childs.push({ id: el.id, name: el.name, parent_id: el.parent_id });
      }
    });
    return acc.concat({ ...val, childs });
  }, []);
};
console.log(generateChild(arr));

output:
(9) [{...}, {...}, {...}, {...}, {...}, ...]
0
:
(4) {id: "1234", parent_id: "", name: "j...}
1
:
(4) {id: "4567", parent_id: "1234", name...}
2
:
(4) {id: "7891", parent_id: "", name: "t...}
3
:
(4) {id: "9876", parent_id: "1234", name...}
4
:
(4) {id: "1357", parent_id: "7891", name...}
5
:
(4) {id: "6789", parent_id: "7891", name...}
6
:
(4) {id: "7892", parent_id: "4567", name...}
7
:
(4) {id: "8765", parent_id: "4567", name...}
8`enter code here`
:
(4) {id: "9108", parent_id: "1234", name...}

1 Comment

Your answer could be improved with additional supporting information. Please edit to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers in the help center.

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.