我有类似的类似问题:JavaScript: Find all parents for element in tree recursive
但是我找不到name
而是direct path
的路径。
const path = ["name1", "name4", "name5"];
const data = [
{
'name': 'name1',
'tree': [
{'name': 'name2'},
{'name': 'name3'},
{
'name': 'name4',
'tree': [
{'name': 'name5'},
{'name': 'name6'}
]
},
{'name': 'name7'}
]
},
{
'name': 'name8',
'tree': [
{'name': 'name9'}
]
}
];
它返回所有可能的路径,或者不返回任何内容。
path
太短时,它什么也不返回。
path
太长时,它什么也不返回。
感谢帮助!
所需输出示例:
const path = ["name1", "name4", "name5"];
findAPath(data, path)
返回:["name1", "name4", "name5"]
const path = ["name1", "name7", "name5"];
findAPath(data, path)
返回[]
const path = ["name1", "name4", "name5", "name5"];
findAPath(data, path)
返回[]
我的尝试:
let index = 0;
function find(data, index) {
let index = index;
data.some((o) => {
if(o.name == path[index]) {
index++;
find(o.tree, index);
}
});
// I don't know what return here.
// I need to probably return path where I am.
return <>;
}
答案 0 :(得分:3)
使用Array.prototype.flatMap
这是使用mutual recursion技术的功能解决方案-
const None =
Symbol ()
const findPath = (tree = [], names = [], r = []) =>
tree.length && names.length // base: and
? tree.flatMap(branch => findPath1(branch, names, r))
: tree.length || names.length // inductive: xor
? []
: [ r ] // inductive: nor // inductive: nor
const findPath1 = ({ name = "", tree = [] } = {}, [ q = None, ...more ] = [], r = []) =>
name === "" && q === None // base: and
? [ r ]
: name === "" || q === None || name !== q // inductive: xor
? []
: findPath(tree, more, [ ...r, q ]) // inductive: nor
findPath(data, ["name1", "name4", "name5"])
// => [ [ "name1", "name4", "name5" ] ]
注意,如果您的数据包含输入值的多个路径,则将返回所有路径-
const data = [
{
'name': 'name1', // name1
'tree': [
{'name': 'name2'},
{'name': 'name3'},
{
'name': 'name4', // name1->name4
'tree': [
{'name': 'name5'}, // name1->name4->name5
{'name': 'name6'}
]
},
{
'name': 'name4', // name1->name4
'tree': [
{'name': 'name5'}, // name1->name4->name5
{'name': 'name6'}
]
},
{'name': 'name7'}
]
},
{
'name': 'name8',
'tree': [
{'name': 'name9'}
]
}
]
就像您问的那样,它返回所有可能的路径,或者什么都不返回-
findPath(data, ["name1", "name4", "name5"])
// => [ [ "name1", "name4", "name5" ],
// [ "name1", "name4", "name5" ] ]
findPath(data, [ "name1", "name7" ])
// => [ [ "name1", "name7" ] ]
findPath(data, [ "name1", "name9" ])
// => []
当路径太短或太长时,它将不返回任何内容-
findPath(data, [ "name1", "name4" ])
// => []
findPath(data, [ "name1", "name4", "name5", "name6" ])
// => []
展开以下代码段,以在您自己的浏览器中验证结果-
const None =
Symbol ()
const findPath = (tree = [], names = [], r = []) =>
tree.length && names.length
? tree.flatMap(branch => findPath1(branch, names, r))
: tree.length || names.length
? []
: [ r ]
const findPath1 = ({ name = "", tree = [] } = {}, [ q = None, ...more ] = [], r = []) =>
name === "" && q === None
? [ r ]
: name === "" || q === None || name !== q
? []
: findPath(tree, more, [ ...r, q ])
const data = [
{
'name': 'name1',
'tree': [
{'name': 'name2'},
{'name': 'name3'},
{
'name': 'name4',
'tree': [
{'name': 'name5'},
{'name': 'name6'}
]
},
{'name': 'name7'}
]
},
{
'name': 'name8',
'tree': [
{'name': 'name9'}
]
}
]
console.log(findPath(data, ["name1", "name4", "name5"]))
// [ [ "name1", "name4", "name5" ] ]
console.log(findPath(data, [ "name1", "name7" ]))
// [ [ "name1", "name7" ] ]
console.log(findPath(data, [ "name1", "name9" ]))
// []
使用生成器
这是使用生成器的另一种实现方式-
const None =
Symbol ()
const findPath = function* (tree = [], names = [], r = [])
{ if (tree.length && names.length) // base: and
for (const branch of tree)
yield* findPath1(branch, names, r)
else if (tree.length || names.length) // inductive: xor
return
else // inductive: nor
yield r
}
const findPath1 = function* ({ name = "", tree = [] } = {}, [ q = None, ...more ] = [], r = [])
{ if (name === "" && q === None) // base: and
yield r
else if (name === "" || q === None || name !== q) // inductive: xor
return
else // inductive: nor
yield* findPath(tree, more, [ ...r, q ])
}
它具有与上面完全相同的输出,只是为了将可迭代生成器强制为数组,我们使用Array.from
-
Array.from(findPath(data, ["name1", "name4", "name5"]))
// => [ [ "name1", "name4", "name5" ] ]
Array.from(findPath(data, [ "name1", "name7" ]))
// => [ [ "name1", "name7" ] ]
Array.from(findPath(data, [ "name1", "name9" ]))
// => []
展开以下代码段,以在您自己的浏览器中验证结果-
const None =
Symbol ()
const findPath = function* (tree = [], names = [], r = [])
{ if (tree.length && names.length)
for (const branch of tree)
yield* findPath1(branch, names, r)
else if (tree.length || names.length)
return
else
yield r
}
const findPath1 = function* ({ name = "", tree = [] } = {}, [ q = None, ...more ] = [], r = [])
{ if (name === "" && q === None)
yield r
else if (name === "" || q === None || name !== q)
return
else
yield* findPath(tree, more, [ ...r, q ])
}
const data = [
{
'name': 'name1',
'tree': [
{'name': 'name2'},
{'name': 'name3'},
{
'name': 'name4',
'tree': [
{'name': 'name5'},
{'name': 'name6'}
]
},
{'name': 'name7'}
]
},
{
'name': 'name8',
'tree': [
{'name': 'name9'}
]
}
]
console.log(Array.from(findPath(data, ["name1", "name4", "name5"])))
// [ [ "name1", "name4", "name5" ] ]
console.log(Array.from(findPath(data, [ "name1", "name7" ])))
// [ [ "name1", "name7" ] ]
console.log(Array.from(findPath(data, [ "name1", "name9" ])))
// []
它们如何相同;他们怎么不是
请注意两个实现之间的相似之处以及结果的形成方式。两者都使用相互递归。功能解决方案使用表达式,而生成器解决方案使用语句。生成器实现扩展了一个明显的优势,即我们可以根据需要选择停止或继续迭代(“查找”)。
例如,假设一个输入中给定输入有十(10)条唯一路径。也许我们只想返回第一场比赛,
const findFirst = (tree = [], names = []) =>
{ for (const path of findPath(tree, names))
return path
}
或获得前三(3)场比赛-
const findFirst3 = (tree = [], names = []) =>
{ const r = []
for (const path of findPath(tree, names))
if (r.length < 3)
r.push(path)
return r
}
或获得第一个N
-
const findFirstN = (tree = [], names = [], n = 0) =>
{ const r = []
for (const path of findPath(tree, names))
if (r.length < n)
r.push(path)
return r
}
这样的发电机很灵活。相比之下,flatMap
实现非常渴望,并且总是返回 all 结果。