簡體   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