6

我想在嵌套的 JSON 对象中搜索字符串。如果在对象中找到字符串,我需要返回该对象。

我正在使用递归函数来实现这一点。问题是,该函数一直递归到结束并且不返回找到的对象。

请在 jsfiddle 中查看整个代码

function search(obj, name) {
    console.log(obj["name"], ",", name, obj["name"] == name);

    if (obj["name"] == name) {
        return obj; //NOT RETURNING HERE
    } 
    if (obj.children || obj._children) {
        var ch = obj.children || obj._children;
        //console.log(ch);
        ch.forEach(function(val) {
            search(val, name)
        });
    }
    return -1;
}

search(myJson, "VM10-Proc4")

我不确定出了什么问题。

4

5 回答 5

8

当它找到匹配的孩子时,您需要停止循环遍历孩子。

function search(obj, name) {

    console.log(obj.name, ",", name, obj.name == name);

    if (obj.name == name) {
        return obj;
    }
    if (obj.children || obj._children) {
        var ch = obj.children || obj._children;
        for (var i = 0; i < ch.length; i++) {
            var found = search(ch[i], name);
            if (found) {
                return found;
            }
        }
    }
    return false;
}

小提琴演示

于 2013-03-28T05:15:46.803 回答
5

正确的返回值在递归函数调用链中丢失了。找到正确的值后,从该点开始进行的任何其他搜索都将返回不正确的值。

处理此问题的几种方法:

1.取消搜索

当找到正确的值时,立即将其返回到递归堆栈,不再搜索当前数组或嵌套数组。换句话说,取消其余的搜索。

@Barmer 的回答就是一个例子。他的代码的关键部分是使用for循环而不是each遍历数组的方法,因为中断循环要容易得多for

2. 将值存储在安全的地方

找到正确的值后,将其存储在安全的地方,让其余的搜索继续,并在初始函数调用完成后访问该值。最简单的方法是将正确的值存储在全局变量中,但这不是一个好习惯,因为它违反了函数的封装。

@shyam 的回答提供了一个更简洁的解决方案:将对全局变量的引用作为函数参数传递,在找到正确值时设置参数,然后在初始函数调用完成后访问全局变量。

在两者之间进行选择

通俗地说,该函数的预期逻辑可以总结如下:当你找到你要找的东西时,停下来,并立即告诉我它是什么。继续搜索的唯一原因是需要找到多条数据。我假设这里不是这种情况。

在这两种方法中,#2 是一种快速修复的解决方法,应该可以正常工作,但会进一步混淆任何试图理解函数预期逻辑的人。如果只寻找已经找到的单条数据,为什么还要继续搜索呢?

#1 是对函数的重构,使其行为与预期逻辑更加一致,这将使函数更易于理解。该函数在找到所需内容时停止搜索。

于 2013-03-28T05:14:57.100 回答
2

我知道这是一篇旧帖子,但我可以看到 2 个问题:

1)递归调用没有返回调用堆栈的结果,即

search(val, name)

应该

return search(val, name)

2) 看起来您正在使用array.forEach()。该文档指出:

除了抛出异常之外,没有其他方法可以停止或中断 forEach() 循环。如果您需要这种行为,那么 forEach() 方法是错误的工具。请改用普通循环。如果您正在测试谓词的数组元素并且需要布尔返回值,则可以使用 every() 或 some() 代替。如果可用,新方法 find() 或 findIndex() 也可用于在真谓词上提前终止。

这意味着,实际上,当您找到要查找的结果时,您希望将其发送回调用堆栈。使用 array.forEach 将继续递归地查看层次结构并返回所有值,而不仅仅是您感兴趣的值。因此最后返回的值可能是您不期望的值,例如 undefined!因此使用不同的迭代方法,即

    for (var i = 0; i < ch.length; i++) {
        var val = ch[i];
        return search(val, name, ret);
    }

接受的答案确实会为您提供部分答案,但没有解释原因。因此这个答案

于 2017-11-14T19:59:40.243 回答
1

由于您正在递归,因此返回可能嵌套得太深而无法获得有意义的结果。相反,您可以尝试传递一个额外的参数来收集结果。

function search(obj, name, ret) {
  console.log(obj["name"], ",", name, obj["name"] == name);

  if (obj["name"] == name) {
    ret.push(obj);
    return
  }
  if (obj.children || obj._children) {
    var ch = obj.children || obj._children;
    ch.forEach(function(val) {
      search(val, name, ret);
    });
  }
}

var result = [];
search(myJson, "VM10-Proc4", result)
于 2013-03-28T05:19:02.977 回答
0

这是使用对象扫描的解决方案

// const objectScan = require('object-scan');

const myJson = {"name":"UCS - San Jose","type":"Minor","children":[{"name":"VM1","type":"Clear","children":[{"name":"VM1-Proc1","type":"Clear","children":[{"name":"VM1-Proc1-child1","type":"Clear"}]},{"name":"VM1-Proc2","type":"Clear"},{"name":"VM1-Proc3","type":"Clear"},{"name":"VM1-Proc4","type":"Clear"},{"name":"VM1-Proc5","type":"Clear"},{"name":"VM1-Proc6","type":"Clear"},{"name":"VM1-Proc7","type":"Clear"},{"name":"VM1-Proc8","type":"Clear"},{"name":"VM1-Proc9","type":"Clear"},{"name":"VM1-Proc10","type":"Clear"}]},{"name":"VM2","type":"Clear","children":[{"name":"VM2-Proc1","type":"Clear"},{"name":"VM2-Proc2","type":"Clear"},{"name":"VM2-Proc3","type":"Clear"},{"name":"VM2-Proc4","type":"Clear"},{"name":"VM2-Proc5","type":"Clear"},{"name":"VM2-Proc6","type":"Clear"},{"name":"VM2-Proc7","type":"Clear"},{"name":"VM2-Proc8","type":"Clear"},{"name":"VM2-Proc9","type":"Clear"},{"name":"VM2-Proc10","type":"Clear"}]},{"name":"VM3","type":"Clear","children":[{"name":"VM3-Proc1","type":"Clear"},{"name":"VM3-Proc2","type":"Clear"},{"name":"VM3-Proc3","type":"Clear"},{"name":"VM3-Proc4","type":"Clear"},{"name":"VM3-Proc5","type":"Clear"},{"name":"VM3-Proc6","type":"Clear"},{"name":"VM3-Proc7","type":"Clear"},{"name":"VM3-Proc8","type":"Clear"},{"name":"VM3-Proc9","type":"Clear"},{"name":"VM3-Proc10","type":"Clear"}]},{"name":"VM4","type":"Minor","children":[{"name":"VM4-Proc1","type":"Clear"},{"name":"VM4-Proc2","type":"Clear"},{"name":"VM4-Proc3","type":"Minor"},{"name":"VM4-Proc4","type":"Clear"},{"name":"VM4-Proc5","type":"Clear"},{"name":"VM4-Proc6","type":"Minor"},{"name":"VM4-Proc7","type":"Clear"},{"name":"VM4-Proc8","type":"Clear"},{"name":"VM4-Proc9","type":"Clear"},{"name":"VM4-Proc10","type":"Clear"}]},{"name":"VM5","type":"Clear","children":[{"name":"VM5-Proc1","type":"Clear"},{"name":"VM5-Proc2","type":"Clear"},{"name":"VM5-Proc3","type":"Clear"},{"name":"VM5-Proc4","type":"Clear"},{"name":"VM5-Proc5","type":"Clear"},{"name":"VM5-Proc6","type":"Clear"},{"name":"VM5-Proc7","type":"Clear"},{"name":"VM5-Proc8","type":"Clear"},{"name":"VM5-Proc9","type":"Clear"},{"name":"VM5-Proc10","type":"Clear"}]},{"name":"VM6","type":"Minor","children":[{"name":"VM6-Proc1","type":"Clear"},{"name":"VM6-Proc2","type":"Clear"},{"name":"VM6-Proc3","type":"Minor"},{"name":"VM6-Proc4","type":"Clear"},{"name":"VM6-Proc5","type":"Clear"},{"name":"VM6-Proc6","type":"Clear"},{"name":"VM6-Proc7","type":"Minor"},{"name":"VM6-Proc8","type":"Clear"},{"name":"VM6-Proc9","type":"Clear"},{"name":"VM6-Proc10","type":"Clear"}]},{"name":"VM7","type":"Clear","children":[{"name":"VM7-Proc1","type":"Clear"},{"name":"VM7-Proc2","type":"Clear"},{"name":"VM7-Proc3","type":"Clear"},{"name":"VM7-Proc4","type":"Clear"},{"name":"VM7-Proc5","type":"Clear"},{"name":"VM7-Proc6","type":"Clear"},{"name":"VM7-Proc7","type":"Clear"},{"name":"VM7-Proc8","type":"Clear"},{"name":"VM7-Proc9","type":"Clear"},{"name":"VM7-Proc10","type":"Clear"}]},{"name":"VM8","type":"Clear","children":[{"name":"VM8-Proc1","type":"Clear"},{"name":"VM8-Proc2","type":"Clear"},{"name":"VM8-Proc3","type":"Clear"},{"name":"VM8-Proc4","type":"Clear"},{"name":"VM8-Proc5","type":"Clear"},{"name":"VM8-Proc6","type":"Clear"},{"name":"VM8-Proc7","type":"Clear"},{"name":"VM8-Proc8","type":"Clear"},{"name":"VM8-Proc9","type":"Clear"},{"name":"VM8-Proc10","type":"Clear"}]},{"name":"VM9","type":"Clear","children":[{"name":"VM9-Proc1","type":"Clear"},{"name":"VM9-Proc2","type":"Clear"},{"name":"VM9-Proc3","type":"Clear"},{"name":"VM9-Proc4","type":"Clear"},{"name":"VM9-Proc5","type":"Clear"},{"name":"VM9-Proc6","type":"Clear"},{"name":"VM9-Proc7","type":"Clear"},{"name":"VM9-Proc8","type":"Clear"},{"name":"VM9-Proc9","type":"Clear"},{"name":"VM9-Proc10","type":"Clear"}]},{"name":"VM10","type":"Clear","children":[{"name":"VM10-Proc1","type":"Clear"},{"name":"VM10-Proc2","type":"Clear"},{"name":"VM10-Proc3","type":"Clear"},{"name":"VM10-Proc4","type":"Clear"},{"name":"VM10-Proc5","type":"Clear"},{"name":"VM10-Proc6","type":"Clear"},{"name":"VM10-Proc7","type":"Clear"},{"name":"VM10-Proc8","type":"Clear"},{"name":"VM10-Proc9","type":"Clear"},{"name":"VM10-Proc10","type":"Clear"}]}]};

const search = (obj, name) => objectScan(['**.name'], {
  rtn: 'parent',
  abort: true,
  filterFn: ({ value }) => value === name
})(obj);

console.log(search(myJson, 'VM10-Proc4'));
// => { name: 'VM10-Proc4', type: 'Clear' }
.as-console-wrapper {max-height: 100% !important; top: 0}
<script src="https://bundle.run/object-scan@13.7.1"></script>

免责声明:我是对象扫描的作者

于 2020-12-27T06:02:50.097 回答