Lets say if we have a deeply nested comment of comments.
const comments = [
{
id: 1,
text: "Comment 1",
comments: [
{
id: 11,
text: "Comment 1a",
comments: [
{
id: 111,
text: "Comment 11a",
comments: [],
},
{
id: 112,
text: "Comment 11b",
comments: [],
},
{
id: 113,
text: "Comment 11c",
comments: [],
},
],
},
{
id: 12,
text: "Comment 12",
comments: [
{
id: 121,
text: "Comment 12a",
comments: [],
},
{
id: 122,
text: "Comment 12b",
comments: [],
},
{
id: 123,
text: "Comment 12c",
comments: [],
},
],
},
{
id: 13,
text: "Comment 1c",
comments: [
{
id: 124,
text: "Comment 13a",
comments: [],
},
{
id: 125,
text: "Comment 13b",
comments: [],
},
{
id: 126,
text: "Comment 13c",
comments: [],
},
],
},
],
},
{
id: 2,
text: "Comment 2",
comments: [
{
id: 21,
text: "Comment 2a",
comments: [
{
id: 127,
text: "Comment 21a",
comments: [],
},
{
id: 128,
text: "Comment 21b",
comments: [],
},
{
id: 129,
text: "Comment 21c",
comments: [
{
id: 130,
text: "Comment 21cc",
comments: [
{
id: 131,
text: "Comment 21ccc",
comments: [],
},
],
},
],
},
],
},
{
id: 22,
text: "Comment 2b",
comments: [
{
id: 135,
text: "Comment 21a",
comments: [],
},
{
id: 132,
text: "Comment 21b",
comments: [],
},
{
id: 133,
text: "Comment 21c",
comments: [],
},
],
},
{
id: 23,
text: "Comment 2c",
comments: [],
},
],
},
{
id: 3,
text: "Comment 3",
comments: [
{
id: 31,
text: "Comment 3a",
comments: [],
},
{
id: 32,
text: "Comment 3b",
comments: [],
},
{
id: 33,
text: "Comment 3c",
comments: [],
},
],
},
];
How would we find a deeply nested comment such as comment with the id of 131? I tried the following and it works.
function recursiveFind(comments, commentId) {
const result = [];
function loop(comments, commentId, result) {
for (const comment of comments) {
if (comment.id === commentId) {
result.push(comment);
}
if (result.length <= 0 && comment.comments) {
loop(comment.comments, commentId, result);
}
}
}
loop(comments, commentId, result);
return result.length > 0 ? result[0] : false;
}
const found = recursiveFind(comments, 131);
console.log(found);//returns object
Is there a more elegant way to do this ? I know another option would be flattening the array and then returning the object?
However, is there a better way to do this ?
Thank you.
Edit: Yes ID is unique, I have corrected the id.
CodePudding user response:
We already have a free tree walker in JS - JSON.stringify
:
function find(data, fn) {
let found = []
JSON.stringify(data, (key, val) => {
if (fn(val))
found.push(val)
return val
})
return found
}
and then simply:
results = find(comments, x => x.id === 131)
CodePudding user response:
You can use a .reduce()
and a recursion:
const comments = [ { id: 1, text: "Comment 1", comments: [ { id: 11, text: "Comment 1a", comments: [ { id: 111, text: "Comment 11a", comments: [], }, { id: 112, text: "Comment 11b", comments: [], }, { id: 113, text: "Comment 11c", comments: [], }, ], }, { id: 12, text: "Comment 12", comments: [ { id: 121, text: "Comment 12a", comments: [], }, { id: 122, text: "Comment 12b", comments: [], }, { id: 123, text: "Comment 12c", comments: [], }, ], }, { id: 13, text: "Comment 1c", comments: [ { id: 124, text: "Comment 13a", comments: [], }, { id: 125, text: "Comment 13b", comments: [], }, { id: 126, text: "Comment 13c", comments: [], }, ], }, ], }, { id: 2, text: "Comment 2", comments: [ { id: 21, text: "Comment 2a", comments: [ { id: 127, text: "Comment 21a", comments: [], }, { id: 128, text: "Comment 21b", comments: [], }, { id: 129, text: "Comment 21c", comments: [ { id: 130, text: "Comment 21cc", comments: [ { id: 131, text: "Comment 21ccc", comments: [], }, ], }, ], }, ], }, { id: 22, text: "Comment 2b", comments: [ { id: 130, text: "Comment 21a", comments: [], }, { id: 132, text: "Comment 21b", comments: [], }, { id: 133, text: "Comment 21c", comments: [], }, ], }, { id: 23, text: "Comment 2c", comments: [], }, ], }, { id: 3, text: "Comment 3", comments: [ { id: 31, text: "Comment 3a", comments: [], }, { id: 32, text: "Comment 3b", comments: [], }, { id: 33, text: "Comment 3c", comments: [], }, ], }, ];
function recursiveFind(comments, commentId) {
const result = comments.reduce((acc, obj) => {
if(obj.id === commentId) {
acc = obj;
} else if(obj.comments.length) {
const found = recursiveFind(obj.comments, commentId);
if(found) acc = found;
}
return acc;
}, null);
return result;
}
console.log('search id 131:', recursiveFind(comments, 131));
Output:
{
"id": 131,
"text": "Comment 21ccc",
"comments": []
}
Docs: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce
UPDATE 1 to address feedback that IDs are not unique. I also remove nested comments; if thatit desired, remove the .map(obj => ({ id: obj.id, text: obj.text }))
UPDATE 2 reverted update 1 since IDs are actually unique.