“我正在尝试递归搜索一个包含字符串、数组和其他对象的对象,以在最深层次上找到一个项目(匹配一个值),但是我总是得到未定义的返回结果。 "
var foundIt = findItem('glasses', theCobWeb);
console.log('The item is here: ' + foundIt); // The item is here: undefined
“物品在这里……” – 在哪里?
那么你到底想要什么作为返回值?完成后是否应该只说"glasses"?在我看来,这有点毫无意义——从根本上说,这并不比只返回true 或false 更好。
我前段时间写了这个函数,因为我需要搜索一堆数据,但还要知道它具体匹配的位置。我现在可能会稍微修改一下(或者至少包括类型注释),但它按原样工作,所以你去吧。
// helpers
const keys = Object.keys
const isObject = x=> Object(x) === x
const isArray = Array.isArray
const rest = ([x,...xs])=> xs
// findDeep
const findDeep = (f,x) => {
let make = (x,ks)=> ({node: x, keys: ks || keys(x)})
let processNode = (parents, path, {node, keys:[k,...ks]})=> {
if (k === undefined)
return loop(parents, rest(path))
else if (isArray(node[k]) || isObject(node[k]))
return loop([make(node[k]), make(node, ks), ...parents], [k, ...path])
else if (f(node[k], k))
return {parents, path: [k,...path], node}
else
return loop([{node, keys: ks}, ...parents], path)
}
let loop = ([node,...parents], path) => {
if (node === undefined)
return {parents: [], path: [], node: undefined}
else
return processNode(parents, path, node)
}
return loop([make(x)], [])
}
// your sample data
var theCobWeb = {biggestWeb: {item: "comb",biggerWeb: {items: ["glasses", "paperclip", "bubblegum"],smallerWeb: {item: "toothbrush",tinyWeb: {items: ["toenails", "lint", "wrapper", "homework"]}}},otherBigWeb: {item: "headphones"}}};
// find path returns {parents, path, node}
let {path, node} = findDeep((value,key)=> value === "glasses", theCobWeb)
// path to get to the item, note it is in reverse order
console.log(path) // => [0, 'items', 'biggerWeb', 'biggestWeb']
// entire matched node
console.log(node) // => ['glasses', 'paperclip', 'bubblegum']
这里的基本直觉是node[path[0]] === searchTerm
匹配查询的完整路径
我们得到匹配数据的整个关键路径。这很有用,因为我们可以根据搜索的根确切地知道它在哪里。要验证路径是否正确,请参阅此示例
const lookup = ([p,...path], x) =>
(p === undefined) ? x : lookup(path,x)[p]
lookup([0, 'items', 'biggerWeb', 'biggestWeb'], theCobWeb) // => 'glasses'
不匹配的查询
请注意,如果我们搜索未找到的内容,node 将是 undefined
let {path, node} = findDeep((value,key)=> value === "sonic the hog", theCobWeb)
console.log(path) // => []
console.log(node) // => undefined
搜索特定的键/值对
搜索函数接收value 和key 参数。随心所欲地使用它们
let {path, node} = findDeep((value,key)=> key === 'item' && value === 'toothbrush', theCobWeb)
console.log(path) // => [ 'item', 'smallerWeb', 'biggerWeb', 'biggestWeb' ]
console.log(node) // => { item: 'toothbrush', tinyWeb: { items: [ 'toenails', 'lint', 'wrapper', 'homework' ] } }
短路 - 150cc
哦,因为我宠坏了你,findDeep 会在找到第一个匹配项后尽快返回。它不会浪费计算周期并在知道答案后继续遍历您的一堆数据。这是一件好事。
去探索
要有勇气,敢于冒险。上面的 findDeep 函数还为返回的对象提供了 parents 属性。它在某些方面可能对您有用,但解释起来有点复杂,对于回答问题并不是很重要。为了简化这个答案,我只提一下它。