我需要使用javascript(可能是在lodash的帮助下)以深度嵌套的对象数组递归过滤对象。 什么是最干净的方法,如果我不知道数组中将有多少个嵌套对象?
假设我具有以下结构
totalVal = topItems["Price"].sum()
topFiveItems = pd.DataFrame({
"Item Name": itemNames,
"Purchase Count": purchaseCount,
"Item Price": itemPrices.map("${:.2f}".format),
"Total Purchase Value": totalVal.map("${:.2f}".format)
})
topFiveItems.sort_values(ascending = False, by = "Total Purchase Value").head()
我想找到带有[
{
label: "first",
id: 1,
children: []
},
{
label: "second",
id: 2,
children: [
{
label: "third",
id: 3,
children: [
{
label: "fifth",
id: 5,
children: []
},
{
label: "sixth",
id: 6,
children: [
{
label: "seventh",
id: 7,
children: []
}
]
}
]
},
{
label: "fourth",
id: 4,
children: []
}
]
}
];
的那个,如果有子对象,则返回true,否则返回false。
当然,如果我具有类似的数据结构,但项目数不同,那么它也应该可以工作。
答案 0 :(得分:5)
由于您只需要true
中的false
个答案,因此可以在递归上使用some()
,有效地进行深度优先搜索,并且使其简洁:
let arr = [{label: "first",id: 1,children: []},{label: "second",id: 2,children: [{label: "third",id: 3,children: [{label: "fifth",id: 5,children: []},{label: "sixth",id: 6,children: [{label: "seventh",id: 7,children: []}]}]},{label: "fourth",id: 4,children: []}]}];
function findNested(arr, id) {
let found = arr.find(node => node.id === id)
return found
? found.children.length > 0
: arr.some((c) => findNested(c.children, id))
}
console.log(findNested(arr, 6)) // True: found with children
console.log(findNested(arr, 7)) // False: found no children
console.log(findNested(arr, 97)) // False: not found
答案 1 :(得分:1)
也许递归式的解决方案可能对您有用?在此,通过提供的输入数据的“子级”递归搜索具有提供的id的节点。如果找到具有匹配ID的子节点,则根据该节点children
数组中数据的存在情况返回布尔结果:
function nodeWithIdHasChildren(children, id) {
for(const child of children) {
// If this child node matches supplied id, then check to see if
// it has data in it's children array and return true/false accordinly
if(child.id === id) {
if(Array.isArray(child.children) && child.children.length > 0) {
return true
}
else {
return false
}
}
else {
const result = nodeWithIdHasChildren(child.children, id);
// If result returned from this recursion branch is not undefined
// then assume it's true or false from a node matching the supplied
// id. Pass the return result up the call stack
if(result !== undefined) {
return result
}
}
}
}
const data = [
{
label: "first",
id: 1,
children: []
},
{
label: "second",
id: 2,
children: [
{
label: "third",
id: 3,
children: [
{
label: "fifth",
id: 5,
children: []
},
{
label: "sixth",
id: 6,
children: [
{
label: "seventh",
id: 7,
children: []
}
]
}
]
},
{
label: "fourth",
id: 4,
children: []
}
]
}
];
console.log('node 6 has children:', nodeWithIdHasChildren( data, 6 ) )
console.log('node 7 has children:', nodeWithIdHasChildren( data, 7 ) )
console.log('node 100 has children:', nodeWithIdHasChildren( data, 7 ), '(because node 100 does not exist)' )
答案 2 :(得分:0)
还:
function explore(myArray, searchedId) {
for (let i=0; i<myArray.length; i++) {
let el;
if (myArray[i].id == searchedId) {
el = myArray[i];
} else {
el = explore(myArray[i].children, searchedId);
}
if (el) {
return el.children.length > 0;
}
}
}
答案 3 :(得分:0)
您可以使用如下所示的“递归”来检查id
是否有孩子
let arr = [{label: "first",id: 1,children: []},{label: "second",id: 2,children: [{label: "third",id: 3,children: [{label: "fifth",id: 5,children: []},{label: "sixth",id: 6,children: [{label: "seventh",id: 7,children: []}]}]},{label: "fourth",id: 4,children: []}]}];
function hasChildren(arr, id) {
let res = false
for (let d of arr) {
if(d.id == id) return d.children.length > 0
res = res || hasChildren(d.children, id)
if(res) return true
}
return res
}
console.log('id 4 has children? ', hasChildren(arr, 4))
console.log('id 6 has children? ', hasChildren(arr, 6))
答案 4 :(得分:0)
您可以使用三个简单的javascript函数来做到这一点:
// Function to Flatten results
var flattenAll = function(data) {
var result = [];
var flatten = function(arr) {
_.forEach(arr, function(a) {
result.push(a);
flatten(a.children);
});
};
flatten(data);
return result;
};
// Function to search on flattened array
var search = function(flattened, id) {
var found = _.find(flattened, function(d) {
return d.id == id;
});
return found;
};
// Function to check if element is found and have children
var hasChildren = function(element) {
return element && element.children && element.children.length > 0;
}
// Usage, search for id = 6
hasChildren(search(flattenAll(your_data_object), 6))
答案 5 :(得分:0)
这是使用recursion
并仅通过一个Array.find
进行的另一种解决方案:
const data = [ { label: "first", id: 1, children: [] }, { label: "second", id: 2, children: [ { label: "third", id: 3, children: [ { label: "fifth", id: 5, children: [] }, { label: "sixth", id: 6, children: [ { label: "seventh", id: 7, children: [] } ] } ] }, { label: "fourth", id: 4, children: [] } ] } ];
const search = (data, id) => {
var f, s = (d, id) => d.find(x => x.id == id ? f = x : s(x.children, id))
s(data, id)
return f ? f.children.length > 0 : false
}
console.log(search(data, 6)) // True: found with children
console.log(search(data, 7)) // False: found but has no children
console.log(search(data, 15)) // False: not found at all
这个想法是要有一个递归函数,当找到id时会记住该对象。
一旦找到(或者我们知道没有找到条目),就返回子项array length
或返回false
。
如果您想实际返回found object
而不是children.length
的布尔值:
const data = [ { label: "first", id: 1, children: [] }, { label: "second", id: 2, children: [ { label: "third", id: 3, children: [ { label: "fifth", id: 5, children: [] }, { label: "sixth", id: 6, children: [ { label: "seventh", id: 7, children: [] } ] } ] }, { label: "fourth", id: 4, children: [] } ] } ];
const search = (data, id) => {
var f, s = (d, id) => d.find(x => x.id == id ? f = x : s(x.children, id))
s(data, id)
return f
}
console.log(search(data, 6)) // returns only the object with id:6
console.log(search(data, 7)) // returns only the object with id: 7
console.log(search(data, 71)) // returns undefined since nothing was found
答案 6 :(得分:0)
您可以使用generator function来递归地迭代节点,并通过使用Array.prototype.some()
简化用于检查是否存在的逻辑:
const data = [{label:'first',id:1,children:[]},{label:'second',id:2,children:[{label:'third',id:3,children:[{label:'fifth',id:5,children:[]},{label:'sixth',id:6,children:[{label:'seventh',id:7,children:[]}]}]},{label:'fourth',id:4,children:[]}]}];
function * nodes (array) {
for (const node of array) {
yield node;
yield * nodes(node.children);
}
}
const array = Array.from(nodes(data));
console.log(array.some(node => node.id === 6 && node.children.length > 0));
console.log(array.some(node => node.id === 7 && node.children.length > 0));
答案 7 :(得分:0)
JSON.parse
reviver parameter或JSON.stringify
replacer parameter可用于检查所有值,并生成引用节点的平面ID查找对象:
var lookup = {}, json = '[{"label":"first","id":1,"children":[]},{"label":"second","id":2,"children":[{"label":"third","id":3,"children":[{"label":"fifth","id":5,"children":[]},{"label":"sixth","id":6,"children":[{"label":"seventh","id":7,"children":[]}]}]},{"label":"fourth","id":4,"children":[]}]}]'
var result = JSON.parse(json, (key, val) => val.id ? lookup[val.id] = val : val);
console.log( 'id: 2, children count:', lookup[2].children.length )
console.log( 'id: 6, children count:', lookup[6].children.length )
console.log( lookup )
答案 8 :(得分:0)
我建议对deepdash
使用lodash
扩展名:
var id6HasChildren = _.filterDeep(obj,
function(value, key, parent) {
if (key == 'children' && parent.id == 6 && value.length) return true;
},
{ leavesOnly: false }
).length>0;
根据您的情况,这是full test。
答案 9 :(得分:0)
我们现在使用object-scan来满足这样的数据处理需求。一旦将头缠绕在它上,它就会非常强大。这是解决问题的方法
const objectScan = require('object-scan');
const hasChildren = (e) => e instanceof Object && Array.isArray(e.children) && e.children.length !== 0;
const find = (id, input) => {
const match = objectScan(['**'], {
abort: true,
rtn: 'value',
filterFn: ({ value }) => value.id === id
})(input);
return hasChildren(match);
};
const data = [{"label":"first","id":1,"children":[]},{"label":"second","id":2,"children":[{"label":"third","id":3,"children":[{"label":"fifth","id":5,"children":[]},{"label":"sixth","id":6,"children":[{"label":"seventh","id":7,"children":[]}]}]},{"label":"fourth","id":4,"children":[]}]}];
console.log(find(6, data));
// => true
console.log(find(2, data));
// => true
console.log(find(7, data));
// => false
console.log(find(999, data));
// => false