I would like to find the parent of a certain item in a recursive array
{
"uuid": "707a5ffd-68e2-4dbd-b539-128512ba3a0a",
"type": "page",
"items": [
{
"uuid": "9d823429-cc24-444d-a21c-a81357305851",
"title": "1",
"type": "question",
},
{
"type": "section",
"title": "2",
"uuid": "346dec94-124c-4932-bd40-af9dc68f1d27",
"items": [
{
"uuid": "bf0a9ab9-99cc-4833-b3d3-84a97072e85f",
"title": "2.1",
"type": "question",
}
],
},
{
"type": "section",
"title": "3",
"uuid": "4964096d-0de9-4ab1-ace5-e42516d6b866",
"items": [
{
"uuid": "b2170580-1e2e-4fb4-a7b9-a56b79db21b3",
"title": "3.1",
"type": "question",
}
],
}
],
"params": {
"collapsed": false
}
}
I have tried so far:
export const findItemParent = (items, id, parent = null) => {
if (parent && parent.id === id) {
return parent;
}
for (const item of items) {
if (Object.prototype.hasOwnProperty.call(item, 'items')) {
return findItemParent(item.items, id, item);
}
}
return parent;
};
Then I'm calling findItemParent
as:
const data = [{...}]; // the data of the first snipet
// b2170580-1e2e-4fb4-a7b9-a56b79db21b3 -> item with title 3.1
const parent = findItemParent(data, "b2170580-1e2e-4fb4-a7b9-a56b79db21b3");
Whenever I run this code I get the parent being 2
.
In the case above I'm passing the id of the item with title 3.1
so logically the parent is 3
. How can I get the parent of any item given the id?
CodePudding user response:
Using recursion, this is what I've come up with.
The parameter items
, I would say is a tad misleading, I would have used something like root.
const findItemParent = (root, id, parent = null) => {
if (root.uuid === id) return parent;
if ('items' in root) {
for (const i of root.items) {
const r = findItemParent(i, id, root);
if (r) return r;
}
}
return null;
};
const data = {
"uuid": "707a5ffd-68e2-4dbd-b539-128512ba3a0a",
"type": "page",
"items": [
{
"uuid": "9d823429-cc24-444d-a21c-a81357305851",
"title": "1",
"type": "question",
},
{
"type": "section",
"title": "2",
"uuid": "346dec94-124c-4932-bd40-af9dc68f1d27",
"items": [
{
"uuid": "bf0a9ab9-99cc-4833-b3d3-84a97072e85f",
"title": "2.1",
"type": "question",
}
],
},
{
"type": "section",
"title": "3",
"uuid": "4964096d-0de9-4ab1-ace5-e42516d6b866",
"items": [
{
"uuid": "b2170580-1e2e-4fb4-a7b9-a56b79db21b3",
"title": "3.1",
"type": "question",
}
],
}
],
"params": {
"collapsed": false
}
};
const findItemParent = (root, id, parent = null) => {
if (root.uuid === id) return parent;
if ('items' in root) {
for (const i of root.items) {
const r = findItemParent(i, id, root);
if (r) return r;
}
}
return null;
};
const parent = findItemParent(data, "b2170580-1e2e-4fb4-a7b9-a56b79db21b3");
if (parent) console.log(parent.title, parent.type, parent.uuid);
<iframe name="sif1" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>
CodePudding user response:
const findParent = (currentObject, id, parent = null) => {
// If its found return its parent
if (currentObject.uuid === id) return parent;
// Iterate through sub items
for (const item of (currentObject.items) || []) {
// If found return it
const found = findParent(item, id, currentObject);
if (found) return found;
}
// If not found return null;
return null;
};
findParent(el, "346dec94-124c-4932-bd40-af9dc68f1d27");
CodePudding user response:
I would make a map where you have a reference to the parent in the tree. This is helpful if you have a lot of look ups.
const book = {
"uuid": "707a5ffd-68e2-4dbd-b539-128512ba3a0a",
"type": "page",
"items": [
{
"uuid": "9d823429-cc24-444d-a21c-a81357305851",
"title": "1",
"type": "question",
},
{
"type": "section",
"title": "2",
"uuid": "346dec94-124c-4932-bd40-af9dc68f1d27",
"items": [
{
"uuid": "bf0a9ab9-99cc-4833-b3d3-84a97072e85f",
"title": "2.1",
"type": "question",
}
],
},
{
"type": "section",
"title": "3",
"uuid": "4964096d-0de9-4ab1-ace5-e42516d6b866",
"items": [
{
"uuid": "b2170580-1e2e-4fb4-a7b9-a56b79db21b3",
"title": "3.1",
"type": "question",
}
],
}
],
"params": {
"collapsed": false
}
};
function walkTree(group, parentRef, titleMapping) {
titleMapping = titleMapping || {};
group.items.forEach(function (item) {
titleMapping[item.title] = { ...item, parentRef };
if (item.items) walkTree(item, titleMapping[item.title], titleMapping);
});
return titleMapping;
}
const titleMapping = walkTree(book);
console.log(titleMapping["3.1"].parentRef.title);
<iframe name="sif2" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>
Other option is to use a recursive find where you look to see if the items contains the title.
CodePudding user response:
You can use a recursive function to iterate over the items of each item.
const data = {
"uuid": "707a5ffd-68e2-4dbd-b539-128512ba3a0a",
"type": "page",
"items": [
{
"uuid": "9d823429-cc24-444d-a21c-a81357305851",
"title": "1",
"type": "question",
},
{
"type": "section",
"title": "2",
"uuid": "346dec94-124c-4932-bd40-af9dc68f1d27",
"items": [
{
"uuid": "bf0a9ab9-99cc-4833-b3d3-84a97072e85f",
"title": "2.1",
"type": "question",
}
],
},
{
"type": "section",
"title": "3",
"uuid": "4964096d-0de9-4ab1-ace5-e42516d6b866",
"items": [
{
"uuid": "b2170580-1e2e-4fb4-a7b9-a56b79db21b3",
"title": "3.1",
"type": "question",
}
],
}
],
"params": {
"collapsed": false
}
};
function findItemParent(items, id, parent = null) {
if (items.find(item => item.uuid === id)) return { uuid: parent?.uuid, type: parent?.type, title: parent?.title };
for (const item of items) {
let p;
if (item.type === 'section') {
p = findItemParent(item.items, id, item);
}
if (p) return p;
}
}
console.log(findItemParent(data.items, "b2170580-1e2e-4fb4-a7b9-a56b79db21b3"));
<iframe name="sif3" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>