我试图以递归方式搜索包含字符串,数组和其他对象的对象,以便在最深层找到一个项目(匹配一个值)但是我总是将未定义作为返回结果。我可以通过一些控制台日志记录看到我找到了该项目,但它被覆盖了。我知道哪里出错了?
var theCobWeb = {
biggestWeb: {
item: "comb",
biggerWeb: {
items: ["glasses", "paperclip", "bubblegum"],
smallerWeb: {
item: "toothbrush",
tinyWeb: {
items: ["toenails", "lint", "wrapper", "homework"]
}
}
},
otherBigWeb: {
item: "headphones"
}
}
};
function findItem (item, obj) {
var foundItem;
for (var key in obj) {
if (obj[key] === item) {
foundItem = obj;
} else if (Array.isArray(obj[key]) && obj[key].includes(item)) {
foundItem = obj;
} else if (typeof obj[key] === 'object' && !Array.isArray(obj[key])) {
findItem(item, obj[key]);
}
}
return foundItem;
}
var foundIt = findItem('glasses', theCobWeb);
console.log('The item is here: ' + foundIt); // The item is here: undefined
编辑:根据以下反馈清理一下代码。
答案 0 :(得分:1)
function findItem (item, obj) {
for (var key in obj) {
if (obj[key] === item) { // if the item is a property of the object
return obj; // return the object and stop further searching
} else if (Array.isArray(obj[key]) && obj[key].includes(item)) { // if the item is inside an array property of the object
return obj; // return the object and stop the search
} else if (typeof obj[key] === 'object' && !Array.isArray(obj[key])) { // if the property is another object
var res = findItem(item, obj[key]); // get the result of the search in that sub object
if(res) return res; // return the result if the search was successful, otherwise don't return and move on to the next property
}
}
return null; // return null or any default value you want if the search is unsuccessful (must be falsy to work)
}
注1: Array.isArray
和Array.prototype.includes
已经返回布尔值,因此无需针对布尔值进行检查。
注2:您可以使用 NOT运算符(!
)来翻转布尔值。
注3:您必须在找到结果后立即返回结果(如果找到),这样您就不会浪费时间寻找已有的结果。
Note4:搜索的返回结果将是一个对象(如果找到),并且由于对象是通过引用而不是通过值传递的,因此更改该对象的属性将更改原始属性对象也是。
编辑:找到最深的对象:
如果你想找到最深的对象,你必须通过对象obj
中的每个对象和子对象,每次你必须存储对象及其深度(如果深度为结果大于之前的结果当然)。这是带有一些注释的代码(我使用了一个实际上在所有对象上调用的内部函数_find
):
function findItem (item, obj) {
var found = null; // the result (initialized to the default return value null)
var depth = -1; // the depth of the current found element (initialized to -1 so any found element could beat this one) (matched elements will not be assigned to found unless they are deeper than this depth)
function _find(obj, d) { // a function that take an object (obj) and on which depth it is (d)
for (var key in obj) { // for each ...
// first call _find on sub-objects (pass a depth of d + 1 as we are going to a one deep bellow)
if (typeof obj[key] === 'object' && !Array.isArray(obj[key])) {
_find(obj[key], d + 1);
}
// then check if this object actually contain the item (we still at the depth d)
else if (obj[key] === item || (Array.isArray(obj[key]) && obj[key].includes(item))) {
// if we found something and the depth of this object is deeper than the previously found element
if(d > depth) {
depth = d; // then assign the new depth
found = obj; // and assign the new result
}
}
}
}
_find(obj, 0); // start the party by calling _find on the object obj passed to findItem with a depth of 0
// at this point found is either the initial value (null) means nothing is found or it is an object (the deepest one)
return found;
}
答案 1 :(得分:0)
那是因为递归调用没有将返回值赋给变量。 你应该检查递归调用的返回值,如果你有其他逻辑,则返回true或者从for循环中断。
function findItem(item, obj) {
for (var key in obj) {
if (obj[key] === item) {
return obj;
} else if (Array.isArray(obj[key]) === true && obj[key].includes(item) === true) {
return obj;
} else if (typeof obj[key] === 'object' && Array.isArray(obj[key]) === false) {
var foundItem = findItem(item, obj[key]);
if(foundItem)
return foundItem;
}
}
答案 2 :(得分:0)
“我试图以递归方式搜索包含字符串,数组和其他对象的对象,以便在最深层找到一个项目(匹配一个值)但是我总是将其定义为返回结果。 “
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
属性。它在某些方面可能对你有用,但解释起来有点复杂,而且回答这个问题并不是很重要。为了简化这个答案,我只想提到它。