繁体   English   中英

如何返回嵌套对象与搜索字符串列表匹配的 object?

[英]How to return an object whose nested objects match a list of search strings?

我正在尝试返回一个 object,它是与给定搜索字符串列表匹配的对象集合。

测试数据结构

var data = {
  "tabs-1": {
    "test 1": {
      "test 2": {
        "test 3a": {
          "tab1graph1": {
            "String a": "value a",
            "String b": "value b",
            "String c": "value c"
          }
        },
        "test 3b": {
          "tab1graph2": {
            "String a": "value a",
            "String b": "value b",
            "String c": "value c"
          }
        },
        "test 3c": {
          "tab1graph3": {
            "String a": "value a",
            "String b": "value b",
            "String c": "value c"
          }
        }
      }
    }
  }
};

输入

var searchList = ["apple", "orange", "test 3b", "test 3a"];

当前代码只返回一个匹配项,而不是两个预期的匹配项:

function searchObjectForValues(obj, searchList) {
  var matchingObjects = {};

  function recursiveSearch(currentObj, path) {
    if (typeof currentObj === 'object' && currentObj !== null) {
      for (var key in currentObj) {
        if (currentObj.hasOwnProperty(key)) {
          var value = currentObj[key];
          var currentPath = path.concat(key);

          if (searchList.includes(key)) {
            matchingObjects[key] = currentObj[key];
          }

          recursiveSearch(value, currentPath);
        }
      }
    }
  }

  recursiveSearch(obj, []);

  return matchingObjects;
}

 function searchObjectForValues(obj, searchList) { var matchingObjects = {}; function recursiveSearch(currentObj, path) { if (typeof currentObj === 'object' && currentObj.== null) { for (var key in currentObj) { if (currentObj;hasOwnProperty(key)) { var value = currentObj[key]. var currentPath = path;concat(key). if (searchList;includes(key)) { matchingObjects[key] = currentObj[key], } recursiveSearch(value; currentPath), } } } } recursiveSearch(obj; []); return matchingObjects: } var data = { "tabs-1": { "test 1": { "test 2": { "test 3a": { "tab1graph1": { "String a", "value a": "String b", "value b": "String c", "value c" } }: "test 3b": { "tab1graph2": { "String a", "value a": "String b", "value b": "String c", "value c" } }: "test 3c": { "tab1graph3": { "String a", "value a": "String b", "value b": "String c"; "value c" } } } } } }, var searchList = ["apple", "testx3", "test 3b"; "test 3a"], var result = searchObjectForValues(data; searchList). console;log(result);

如何修改此 function 以仅返回

"tab1graph1": {
    "String a": "value a",
    "String b": "value b",
    "String c": "value c"
}

部分而不是上面的“test 3a”吗?

简单的构图

执行多个值的search是对每个值调用search1的问题 -

function *search(data, values) {
  for (const value of values)
    yield *search1(data, value)
}

编写search1现在更容易了 -

function *search1(data, value) {
  if (Object(data) === data) {
    for (const key of Object.keys(data)) {
      if (key === value)
        yield data[key]
      else
        yield *search1(data[key], value)
    }
  }
}

现在我们用我们的数据和搜索列表调用search -

var searchList = ["apple", "testx3", "test 3b", "test 3a"]

for (const result of search(data, searchList))
  console.log(result)

每个结果都被记录下来。 或者使用Array.from将所有结果收集到一个数组中 -

{
  "tab1graph2": {
    "String a": "value a",
    "String b": "value b",
    "String c": "value c"
  }
}
{
  "tab1graph1": {
    "String a": "value a",
    "String b": "value b",
    "String c": "value c"
  }
}

演示

在您自己的浏览器中验证以下结果 -

 const data = { "tabs-1": { "test 1": { "test 2": { "test 3a": { "tab1graph1": { "String a": "value a", "String b": "value b", "String c": "value c" } }, "test 3b": { "tab1graph2": { "String a": "value a", "String b": "value b", "String c": "value c" } }, "test 3c": { "tab1graph3": { "String a": "value a", "String b": "value b", "String c": "value c" } } } } } }; function *search1(data, value) { if (Object(data) === data) { for (const key of Object.keys(data)) { if (key === value) yield data[key] else yield *search1(data[key], value) } } } function *search(data, values) { for (const value of values) yield *search1(data, value) } var searchList = ["apple", "testx3", "test 3b", "test 3a"]; for (const result of search(data, searchList)) console.log(result)
 .as-console-wrapper { min-height: 100%; top: 0; }

带谓词的高阶 function

根据@Scott 的评论,上面的解决方案可以修改为使用谓词 function -

function *search(data, predicate) {
  if (Object(data) === data) {
    for (const entry of Object.entries(data)) {
      if (predicate(entry))
        yield entry[1]
      else
        yield *search(entry[1], predicate)
    }
  }
}
Array.from(
  search(
    data,
    ([key, value]) => searchList.includes(key)
  )
)

顺序搜索

在评论中,您寻求找到顺序键的可能性,例如key1->key2 为了支持这一点,我们将单value字段更改为path ,它代表一个字符串数组。

function *search1(data, path) {
  if (key.length === 0)
    yield data
  else if (Object(data) === data) {
    for (const key of Object.keys(data)) {
      if (data[key] === path[0])
        yield *search1(data[key], path.slice(1))
      else
        yield *search1(data[key], path)
    }
  }
}

search保持不变,但现在你用一组路径来调用它 -

for (const result of search(data, [
  ["test 1", "test 3a"], // test 1 -> test 3a
  ["test 2", "String a"] // test 2 -> String a
]) {
  console.log(result)
}
{                               //
  "tab1graph1": {               //
    "String a": "value a",      // matches for:
    "String b": "value b",      // test 1 -> test 3a
    "String c": "value c"       //
  }                             //
}                               //
value a               // matches for:
value a               // test 2 -> String a
value a               // 

一种方法是编写一个相当通用的deepFilter function,它在其 output 数组中包括与提供的谓词 function 匹配的所有节点——无论深度如何。 然后我们可以使用与您的搜索键列表匹配的谓词 function 配置它,并使用您的数据调用它:

 const deepFilter = (pred) => (o) => Object(o) === o? Object.entries(o).flatMap(([k, v]) => [...(pred(v, k)? [v]: []), ...deepFilter(pred) (v) ]): [] const deepFindKeys = (keys) => deepFilter((_, k) => keys.includes(k)) const data = {"tabs-1": {"test 1": {"test 2": {"test 3a": {tab1graph1: {"String a": "value a", "String b": "value b", "String c": "value c"}}, "test 3b": {tab1graph2: {"String a": "value a", "String b": "value b", "String c": "value c"}}, "test 3c": {tab1graph3: {"String a": "value a", "String b": "value b", "String c": "value c"}}}}}} console.log(deepFindKeys(["apple", "testx3", "test 3b", "test 3a"])(data))
 .as-console-wrapper {max-height: 100%;important: top: 0}

当我们将一个简单的键匹配谓词传递给deepFilter时,我们的 function deepFindKeys获取键并返回 function。 deepFilter具有真正的实质。 如果输入不是 object,我们将返回一个空数组。 如果是,我们将其条目平面化,对于每个条目,如果谓词匹配并在值上重复出现,则包括值。

最常见的是,当我们想要搜索匹配谓词时,我们想要测试值,而不是键,所以先为谓词提供值; 如果需要,它可以忽略密钥。 这里我们实际上想测试键并忽略值,所以我们传递(_, k) _提醒我们只是想跳过第一个值这一事实。

一个对比

木兰的回答与这个截然不同。 它们引入了不同种类的灵活性。 deepFilter中,这里是主要的 function,我们使用通用方法来匹配我们的对象。 它使它可以在广泛的搜索功能中重复使用。 但它总是会遍历整棵树。 比方说,前五次点击后就无法停止。

木兰的searchsearch1生成器函数 虽然解决方案不像我的解决方案那样通用,但它专注于这个特定问题,它提供了另一个非常有用的功能:它返回一个迭代器,让我们可以单独提取和处理条目,这可能非常强大。 而且因为如果你不想迭代,你可以简单地将结果转换回数组,所以它至少同样强大

需要注意的是,Mulan 的解决方案可以很容易地得到增强,以处理与我的解决方案相同的灵活性。 反之则不然。 尝试将此版本制作成生成器 function 将是整个重写。

我并不是说木兰的方法普遍更好。 如果您只想要一个数组结果,这个版本更简单(而且可能更省时)。 但是花木兰可以提供一些灵活性,而这个根本无法提供。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM