[英]Finding value in deep nested array of object, recursively, javascript
I have an array of nested objects, having parent-child relationship:我有一组嵌套对象,具有父子关系:
[
{
"id":"5b9ce8d51dbb85944baddfa5",
"name":"EARBANG",
"parent_id":0,
"status":"Inactive",
"children":[
{
"id":"5b9ce8d5d978f75e4b1584ba",
"name":"DIGINETIC",
"parent_id":"5b9ce8d51dbb85944baddfa5",
"status":"Active",
"children":[
{
"id":"5b9ce8d5cb79d63c8b38018c",
"name":"PREMIANT",
"parent_id":"5b9ce8d5d978f75e4b1584ba",
"status":"Active",
}
]
}
]
},
{
"id":"5b9ce8d51650fac75fa359c8",
"name":"GEEKOLOGY",
"parent_id":0,
"status":"Active",
},
{
"id":"5b9ce8d59f52e801a2e40a97",
"name":"TOYLETRY",
"parent_id":0,
"status":"Inactive",
},
{
"id":"5b9ce8d5d136fcfed2f3e0dd",
"name":"PAPRIKUT",
"parent_id":0,
"status":"Inactive",
},
{
"id":"5b9ce8d53afb7a61e188c48e",
"name":"EYERIS",
"parent_id":0,
"status":"Inactive",
}
]
here I want that :在这里我想要:
1- Find an object having id eg 5b9ce8d51dbb85944baddfa5
1- 找到一个具有 id 的对象,例如
5b9ce8d51dbb85944baddfa5
2- iterate in that objects children array (if non empty) recursively and get id of all its childrends and grand-childrens and great-grand-childrens in an array. 2- 递归迭代该对象的子数组(如果非空),并在数组中获取其所有子、孙子和曾孙子的 id。
So my result will be like所以我的结果会像
{
"id":"5b9ce8d51dbb85944baddfa5",
childs: ["5b9ce8d5d978f75e4b1584ba", "5b9ce8d5cb79d63c8b38018c", ...]
}
I tried some solutions available on stack overflow, but could not get it to work.我尝试了一些堆栈溢出可用的解决方案,但无法使其正常工作。
I appreciate if anyone can help me, my DS not that strong.如果有人可以帮助我,我很感激,我的 DS 没有那么强。
Thanks谢谢
Here is a search recursive function:这是一个搜索递归函数:
function searchRecursive(data, id) {
let found = data.find(d => d.id === id);
if (!found) {
let i = 0;
while(!found && i < data.length) {
if (data[i].children && data[i].children.length) {
found = searchRecursive(data[i].children, id);
}
i++;
}
}
return found;
}
Recursively search for the id.递归搜索id。
const data = [ { "id":"5b9ce8d51dbb85944baddfa5", "name":"EARBANG", "parent_id":0, "status":"Inactive", "children":[ { "id":"5b9ce8d5d978f75e4b1584ba", "name":"DIGINETIC", "parent_id":"5b9ce8d51dbb85944baddfa5", "status":"Active", "children":[ { "id":"5b9ce8d5cb79d63c8b38018c", "name":"PREMIANT", "parent_id":"5b9ce8d5d978f75e4b1584ba", "status":"Active", } ] } ] }, { "id":"5b9ce8d51650fac75fa359c8", "name":"GEEKOLOGY", "parent_id":0, "status":"Active", }, { "id":"5b9ce8d59f52e801a2e40a97", "name":"TOYLETRY", "parent_id":0, "status":"Inactive", }, { "id":"5b9ce8d5d136fcfed2f3e0dd", "name":"PAPRIKUT", "parent_id":0, "status":"Inactive", }, { "id":"5b9ce8d53afb7a61e188c48e", "name":"EYERIS", "parent_id":0, "status":"Inactive", } ]; const search = (data, id) => data.find(d => d.id === id) || search(d.children); console.log(search(data, '5b9ce8d51dbb85944baddfa5'));
Take a look at the code sandbox that I have created which recursively searches for id.看看我创建的代码沙箱,它递归地搜索 id。 Once id is found it calls another recursion to generate child's array.
一旦找到 id,它就会调用另一个递归来生成子数组。
console.log(findId(data, "5b9ce8d51dbb85944baddfa5"));
console.log(findId(data, "5b9ce8d5cb79d63c8b38018c"));
Following is the output for above two.以下是以上两个的输出。
https://codesandbox.io/s/m4vowz8qp8 https://codesandbox.io/s/m4vowz8qp8
You can find the object with a fairly standard recursive approach.您可以使用相当标准的递归方法找到对象。 The edge condition is that the object passed to the function is an array.
边缘条件是传递给函数的对象是数组。 This will do a depth first search for the ID.
这将对 ID 进行深度优先搜索。
Once you find the object you need to get the descendant children.找到对象后,您需要获取后代子项。 I would make this a separate function for simplicity:
为简单起见,我会将其作为一个单独的函数:
const data = [ { "id":"5b9ce8d51dbb85944baddfa5","name":"EARBANG","parent_id":0,"status":"Inactive","children":[ { "id":"5b9ce8d5d978f75e4b1584ba","name":"DIGINETIC","parent_id":"5b9ce8d51dbb85944baddfa5","status":"Active","children":[ { "id":"5b9ce8d5cb79d63c8b38018c","name":"PREMIANT","parent_id":"5b9ce8d5d978f75e4b1584ba","status":"Active",}]}]},{ "id":"5b9ce8d51650fac75fa359c8","name":"GEEKOLOGY","parent_id":0,"status":"Active",},{ "id":"5b9ce8d59f52e801a2e40a97","name":"TOYLETRY","parent_id":0,"status":"Inactive",},{ "id":"5b9ce8d5d136fcfed2f3e0dd","name":"PAPRIKUT","parent_id":0,"status":"Inactive",},{ "id":"5b9ce8d53afb7a61e188c48e","name":"EYERIS","parent_id":0,"status":"Inactive",}]; // create an array of child ids function getChildren(obj) { return (!Array.isArray(obj)) ? [] : obj.reduce((arr, curr) => arr.concat(curr.id, ...getChildren(curr.children)), []) } // find a particular id function search(arr, key){ if (Array.isArray(arr)) { for (obj of arr){ return (obj.id === key) ? {id: obj.id, childs: getChildren(obj.children)} // call getChildren once you've found the object : search(obj.children, key) } } } console.log(search(data, '5b9ce8d51dbb85944baddfa5')); // find deeper nesting: console.log(search(data, '5b9ce8d5d978f75e4b1584ba'));
It will return undefined if the ID is not found.如果未找到 ID,它将返回 undefined。
let input = [ { id: '5b9ce8d51dbb85944baddfa5', name: 'EARBANG', parent_id: 0, status: 'Inactive', children: [ { id: '5b9ce8d5d978f75e4b1584ba', name: 'DIGINETIC', parent_id: '5b9ce8d51dbb85944baddfa5', status: 'Active', children: [ { id: '5b9ce8d5cb79d63c8b38018c', name: 'PREMIANT', parent_id: '5b9ce8d5d978f75e4b1584ba', status: 'Active' } ] } ] }, { id: '5b9ce8d51650fac75fa359c8', name: 'GEEKOLOGY', parent_id: 0, status: 'Active' }, { id: '5b9ce8d59f52e801a2e40a97', name: 'TOYLETRY', parent_id: 0, status: 'Inactive' }, { id: '5b9ce8d5d136fcfed2f3e0dd', name: 'PAPRIKUT', parent_id: 0, status: 'Inactive' }, { id: '5b9ce8d53afb7a61e188c48e', name: 'EYERIS', parent_id: 0, status: 'Inactive' } ]; function getNestedChildrenId(fileteredObject, children) { return fileteredObject.map(item => { children.push(item.id); if (item.children && item.children.length) { getNestedChildrenId(item.children, children); } }); } function getParentAndChildrenId(parentId, data) { let result = { id: parentId, children: [] }; let fileteredParent = data.find(({ id }) => id === parentId); if (fileteredParent.children) getNestedChildrenId(fileteredParent.children, result.children); return result; } console.log(getParentAndChildrenId('5b9ce8d51dbb85944baddfa5', input)); console.log(getParentAndChildrenId('5b9ce8d5d136fcfed2f3e0dd', input));
Here's a basic recursive way,这是一个基本的递归方式,
var data = [{ "id": "5b9ce8d51dbb85944baddfa5", "name": "EARBANG", "parent_id": 0, "status": "Inactive", "children": [{ "id": "5b9ce8d5d978f75e4b1584ba", "name": "DIGINETIC", "parent_id": "5b9ce8d51dbb85944baddfa5", "status": "Active", "children": [{ "id": "5b9ce8d5cb79d63c8b38018c", "name": "PREMIANT", "parent_id": "5b9ce8d5d978f75e4b1584ba", "status": "Active", }] }] }, { "id": "5b9ce8d51650fac75fa359c8", "name": "GEEKOLOGY", "parent_id": 0, "status": "Active", }, { "id": "5b9ce8d59f52e801a2e40a97", "name": "TOYLETRY", "parent_id": 0, "status": "Inactive", }, { "id": "5b9ce8d5d136fcfed2f3e0dd", "name": "PAPRIKUT", "parent_id": 0, "status": "Inactive", }, { "id": "5b9ce8d53afb7a61e188c48e", "name": "EYERIS", "parent_id": 0, "status": "Inactive", }]; function findChildren(obj, output, targetId, found) { var _found; obj.forEach((child) => { if (found || child.id === targetId) { if (found) output.push(child.id); _found = true; } if (child.children && child.children.length) { findChildren(child.children, output, targetId, _found); } }); return output; } var res = findChildren(data, [], "5b9ce8d51dbb85944baddfa5"); console.log('res:', res);
Here is a generic implementation that stops recursing once the predicate function returns true (hopefully we can find gold in our loot):这是一个通用实现,一旦谓词函数返回 true,它就会停止递归(希望我们能在我们的战利品中找到黄金):
var loot = {
box_a: 'seaweed',
box_b: {
box_c: [
{ box_d: 'tuna', box_e: ['gold', 'trash'] }
]
}
};
function descend_obj(item, pred_fn) {
if (item instanceof Array) {
return item.some(it => {
return descend_obj(it, pred_fn);
});
} else if (typeof item === "object") {
return Object.keys(item).some(k => {
return descend_obj(item[k], pred_fn);
});
} else {
return pred_fn(item);
}
}
let hasGold = descend_obj(loot, function isGold(item) {
return (item === 'gold')
});
let msg = (hasGold)
? 'yaaaay!'
: 'awwweee';
console.log(msg);//yaaaay!
You can use this approach:您可以使用这种方法:
var array = [your array];
function filter(array, id) {
result = {
id: id,
children: []
};
array.map(val => {
if (val.id == id) {
findChildren(val, result);
}
});
return result;
}
function findChildren(obj) {
if (obj.children && Array.isArray(obj.children)) {
obj.children.map(val => {
if (val.id) {
result.children.push(val.id);
}
if (val.children) {
findChildren(val);
}
});
}
}
var search = filter(array, '5b9ce8d51dbb85944baddfa5');
I think the code is clear and does not need explanation.我认为代码很清楚,不需要解释。
I tend not to use recursion because recursion is harder to reason about that loops because:我倾向于不使用递归,因为递归更难推理循环,因为:
As far as synchronous code is concerned, recursion can always be replaced with a loop.就同步代码而言,递归总是可以用循环代替。
Here's non recursive solution:这是非递归解决方案:
function findDescendants(data, key) {
let ancestor;
const ancestorStack = [data];
while (ancestorStack.length) { // 1- Find an object having id
const current = ancestorStack.pop();
for (const item of current) {
if (item.id === key) {
ancestor = item;
break;
}
const { children } = current;
if (children && children.length) {
ancestorStack.push(children);
}
}
}
const descendantIds = [];
const childrenStack = [ancestor.children];
while (childrenStack.length) { // 2- get id of all its descendants
const current = childrenStack.pop();
for (const item of current) {
descendantIds.push(item.id);
const { children } = item;
if (children && children.length) {
childrenStack.push(children);
}
}
}
return {
id: ancestor.id,
childs: descendantIds
}
}
live demo: https://repl.it/@marzelin/findDescendants现场演示: https : //repl.it/@marzelin/findDescendants
Since this function performs two independent tasks, it would be good to outsource and generalize the tasks:由于此功能执行两个独立的任务,因此最好将任务外包和泛化:
function findDeep(predicate, deepProps, data)
function gatherDeep(prop, deepProps, data)
Then findDecendants
could be simplified to:然后
findDecendants
可以简化为:
function findDescendants(data, key) {
const ancestor = findDeep(o => o.id === key, ["children"], data);
const descendantIds = gatherDeep("id", ["children"], ancestor.children);
return {
id: ancestor.id,
childs: descendantIds
}
}
I made myself a function for this which might be of use for you as well.我为此创建了一个函数,它也可能对您有用。
It helps a lot when you dont know what kind of object you are dealing with...当你不知道你正在处理什么样的对象时,它会很有帮助......
Example:例子:
var values = [ { "id":"5b9ce8d51dbb85944baddfa5", "name":"EARBANG", "parent_id":0, "status":"Inactive", "children":[ { "id":"5b9ce8d5d978f75e4b1584ba", "name":"DIGINETIC", "parent_id":"5b9ce8d51dbb85944baddfa5", "status":"Active", "children":[ { "id":"5b9ce8d5cb79d63c8b38018c", "name":"PREMIANT", "parent_id":"5b9ce8d5d978f75e4b1584ba", "status":"Active", } ] } ] }, { "id":"5b9ce8d51650fac75fa359c8", "name":"GEEKOLOGY", "parent_id":0, "status":"Active", }, { "id":"5b9ce8d59f52e801a2e40a97", "name":"TOYLETRY", "parent_id":0, "status":"Inactive", }, { "id":"5b9ce8d5d136fcfed2f3e0dd", "name":"PAPRIKUT", "parent_id":0, "status":"Inactive", }, { "id":"5b9ce8d53afb7a61e188c48e", "name":"EYERIS", "parent_id":0, "status":"Inactive", } ] //--------------------------------------------------------- // Strip Down to String Function //---------------------------------------------------------- var depth = 0; var stripdown = function(object, find, eol) { depth = depth + 1; var str = ""; var s = new function() { return { // Unique ID generator id: new Date().getFullYear() + new Date().getMonth() + new Date().getDate() + new Date().getHours() + new Date().getMinutes() + new Date().getSeconds() + new Date().getMilliseconds(), // Spaces for depth space: ' ', // Index index: 0 } }; while(s.index <= Object.keys(object).length){ // Every Last Line Has An Undefined Object So Clear Them if (Object.keys(object)[s.index] != undefined) { // If More Than 1 In The Line Add ',' + eol if (s.index > 0) { str = str + ',' + eol; } // Add Spaces For Each Depth Level for(var i=0;i < depth;i++) { str = str + s.space; } // Add Keys str = str + Object.keys(object)[s.index] + ' : '; // Add Values if (typeof Object.values(object)[s.index] === 'object'){ str = str + '{' + eol; // Starting Tag // Add Inner Object Values str = str + stripdown(Object.values(object)[s.index], find, eol); // Add Closing Space for(var i=depth;i > 0;i--) { str = str + s.space; } str = str + '}'; // Closing Tag // Find Object if(str.indexOf(find)>-1){ // Lower The Depth depth = depth - 1; return str + eol; } } else { // No Sub Object str = str + Object.values(object)[s.index]; } } // Next line s.index = s.index + 1; } // Lower The Depth depth = depth - 1; // Return return str + eol; } //--------------------------------------------------------- console.log(stripdown(values, "PREMIANT", "\\n"));
Usage:用法:
stripdown( [object Object], SearchFor, "\n" );
Returns Object Tree as String;以字符串形式返回对象树;
0 : {
id : 5b9ce8d51dbb85944baddfa5,
name : EARBANG,
parent_id : 0,
status : Inactive,
children : {
0 : {
id : 5b9ce8d5d978f75e4b1584ba,
name : DIGINETIC,
parent_id : 5b9ce8d51dbb85944baddfa5,
status : Active,
children : {
0 : {
id : 5b9ce8d5cb79d63c8b38018c,
name : PREMIANT,
parent_id : 5b9ce8d5d978f75e4b1584ba,
status : Active
}
}
}
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.