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;
}

Noxin D Victus
  • 386
  • 1
  • 5
  • 17
  • 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. – ikhvjs Aug 27 '21 at 14:33
  • @ikhvjs, I updated the result that I wanted to see, thanks for the comment – Noxin D Victus Aug 27 '21 at 14:35
  • What have you tried so far? I think a recursive function approach would be good for your case. – ikhvjs Aug 27 '21 at 14:38
  • @ikhvjs, I tried this one, 3rd answer, https://stackoverflow.com/questions/30714938/lodash-property-search-in-array-and-in-nested-child-arrays with some modifications but I can't seem to find a way to store the name of the parents on result array – Noxin D Victus Aug 27 '21 at 14:45
  • Can you please show us your approach? – ikhvjs Aug 27 '21 at 14:50
  • @ikhvjs, I have added the approach on top, I hope that helps, thanks for your time – Noxin D Victus Aug 27 '21 at 14:55
  • I just notice your object in the children array doesn't have children, your data seems inconsistent, right? It is just a reminder for you in case you miss it. – ikhvjs Aug 27 '21 at 15:22

7 Answers7

2

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"]

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);
Lajos Arpad
  • 64,414
  • 37
  • 100
  • 175
  • 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.? – Johnson Anthony Feb 01 '22 at 10:12
  • @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. – Lajos Arpad Feb 02 '22 at 15:24
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', []);
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');
Jürgen Fink
  • 3,162
  • 2
  • 23
  • 25
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...}
  • 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](/help/how-to-answer). – Community Aug 29 '22 at 19:52
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
    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](/help/how-to-answer). – Community Aug 29 '22 at 19:47
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
    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](/help/how-to-answer). – Community Dec 08 '22 at 07:30