我有对象数组,它们也可以有自己的数组。我的主要目标是在整个树中找到一个具有给定 id 的对象,并通过显示它出现的对象名称的名称来获取该元素的 readmap。
例如我有这样的数据对象:
{
id: '0',
name: "Boys"
children: [
{
name: "Soldiers",
children: [
{
name: "Bravo"
children: [
{name: "Tom"},
{name: "Andrew"}
]
}
]
},
{
name: "Runners",
children: [
{
name: "Team B"
children: [
{name: "Mark"},
{name: "David"}
]
}
]
}
]
}
我目前正在通过函数查找项目
function findByName (name, array) {
for (const node of array) {
if (node.name === name) return node;
if (node.children) {
const child = findByName(name, node.children);
if (child) return child;
}
}
}
但为了实现我的目标,我还需要实现该价值的路线图。例如。
当我想找到 "Tom"
时。除了 findByName
的结果,我还想得到 {name: "Tom", road: ["Boys", "Soldiers", "Bravo"]
答案 0 :(得分:1)
您需要传递另一个处理路径的属性。首先将路径定义为空数组。并且由于您只关心名称,因此每次找到具有子节点的节点时,您都可以将名称推入该数组中。
然后您只需将更新后的数组传递给您的递归函数。请参阅下面的工作示例:
(我更新了你的函数以返回一个包含结果和路径的对象)
function findByName(name, array, path = []) {
for (const node of array) {
if (node.name === name) return {result: node, path};
if (node.children) {
path.push(node.name) // We update the path with the current node name that has children
const child = findByName(name, node.children, path );
if (child) return { result: child, path};
}
}
}
答案 1 :(得分:1)
您可以在调用函数中为每个级别添加路径,而无需移交路径。
const
findByName = (array, name) => {
for (const node of array) {
if (node.name === name) return { ...node, path: [] };
if (node.children) {
const child = findByName(node.children, name);
if (child) return { ...child, path: [node.name, ...child.path] };
}
}
},
data = [{ id: '0', name: "Boys", children: [{ name: "Soldiers", children: [{ name: "Bravo", children: [{ name: "Tom" }, { name: "Andrew" }] }] }, { name: "Runners", children: [{ name: "Team B", children: [{ name: "Mark" }, { name: "David" }] }] }] }];
console.log(findByName(data, 'Tom'));
.as-console-wrapper { max-height: 100% !important; top: 0; }
答案 2 :(得分:1)
我喜欢此类或问题的生成器,因为它允许您select
一个、多个或所有结果。此外,生成器将控制权交给调用者,允许您在对结果满意时停止搜索。这可以通过一个函数来完成 -
function* select(a = [], query = Boolean, path = [])
{ for (const t of a)
{ if (query(t)) yield { ...t, path }
yield *select(t.children, query, [...path, t.name])
}
}
const data =
[{ id: '0', name: "Boys", children: [{ name: "Soldiers", children: [{ name: "Bravo", children: [{ name: "Tom" }, { name: "Andrew" }] }] }, { name: "Runners", children: [{ name: "Team B", children: [{ name: "Mark" }, { name: "David" }] }] }] }]
// select "Tom" OR "Mark"
for (const r of select(data, v => v.name == 'Tom' || v.name == "Mark"))
console.log("found:", r)
found: {
"name": "Tom",
"path": [
"Boys",
"Soldiers",
"Bravo"
]
}
found: {
"name": "Mark",
"path": [
"Boys",
"Runners",
"Team B"
]
}
如果您只想要第一个结果,我们可以使用return
或break
,搜索会立即停止,这可能会节省许多浪费的计算-
function first (it)
{ for (const x of it)
return x // <- return and stop searching
}
first(select(data, v => v.name == "Andrew"))
{
"name": "Andrew",
"path": [
"Boys",
"Soldiers",
"Bravo"
]
}
如果您想要所有结果,我们可以使用Array.from
。因为 select
是灵活的,它允许我们做各种有用的查询 -
Array.from(select(data, v => !v.children), r => r.name)
[
"Tom",
"Andrew",
"Mark",
"David"
]