微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

搜索嵌套的对象数组并返回所有匹配项的完整路径

如何解决搜索嵌套的对象数组并返回所有匹配项的完整路径

我想搜索一个深层嵌套的对象数组,并返回所有匹配对象的路径。我有部分解决问题的方法,但是代码仅返回第一个匹配对象的路径。请查看输入,预期输出代码本身。我在预期的输出部分中评论了所需的逻辑。

先谢谢了。请帮帮我。

输入数据

   [
   {
      "label":"Home","key":"home","level":1,"children":[
         {
            "label":"Indoor Furniture","key":"furniture","level":2,"children":[
               {
                  "label":"Chair","key":"chair","level":3
               },{
                  "label":"Table","key":"table",{
                  "label":"Lamp","key":"lamp","level":3
               }
            ]
         }
      ]
   },{
      "label":"Outdoor","key":"outdoor","children":[
         {
            "label":"Outdoor Furniture","children":[
               {
                  "label":"Trampoline","key":"trampoline",{
                  "label":"Swing","key":"swing",{
                  "label":"Large sofa","key":"large sofa",{
                  "label":"Medium Sofa","key":"mediumSofa",{
                  "label":"Small Sofa Wooden","key":"smallSofaWooden","level":3
               }
            ]
         },{
            "label":"Games","key":"games","children":[
               
            ]
         }
      ]
   },{
      "label":"Refurbrished Items","key":"refurbrished items","children":[
         
      ]
   },{
      "label":"Indoor","key":"indoor","children":[
         {
            "label":"Electicity","key":"electicity","children":[
               
            ]
         },{
            "label":"Living Room Sofa","key":"livingRoomSofa","children":[
               
            ]
         }
      ]
   }
]

预期输出-如果搜索了沙发

[
// Remove the entire object if label of the object itself or any of its children doesn't include sofa
      {
         "label":"Outdoor","children":[
            {
               "label":"Indoor Furniture","key":"indoorFurniture","children":[
// Remove unmatched siblings
                  { `// Child node matched,hence return its path from root (Outdoor -> Indoor Furniture)`  
                     "label":"Large sofa","level":3
                  },{ // Child node matched,hence return its path from root (Outdoor -> Indoor Furniture) and all its children if any
                     "label":"Medium Sofa",hence return its path from root (Outdoor -> Indoor Furniture) and all its children if any
                     "label":"Small Sofa Wooden","level":3
                  }
               ]
            }
         ]
      },{
         "label":"Indoor","children":[
            { // Child node matched,hence return its path from root (Indoor) and all its children if any
               "label":"Living Room Sofa","children":[
                  
               ]
            }
         ]
      }
   ]

预期产量-如果搜索家具

[ // Remove the entire object if label of the object itself or any of its children doesn't include furniture
          {
             "label":"Home","children":[
                { // Child node matched,hence return its path from root (Home) and all its children if any
                   "label":"Indoor Furniture","children":[
                      {
                         "label":"Chair","level":3
                      },{
                         "label":"Table",{
                         "label":"Lamp","level":3
                      }
                   ]
                }
             ]
          },{
             "label":"Outdoor",hence return its path from root (Outdoor) and all its children if any
                   "label":"Outdoor Furniture","key":"outdoorFurniture","children":[
                      {
                         "label":"Trampoline",{
                         "label":"Swing",{
                         "label":"Large sofa",{
                         "label":"Medium Sofa",{
                         "label":"Small Sofa Wooden","level":3
                      }
                   ]
                }
             ]
          }
       ]

代码

function findChild(obj,condition) {
if (Object.entries(condition).every( ([k,v]) => (obj[k].toLowerCase()).includes(v.toLowerCase()))) {
    return obj;
}
for (const child of obj.children || []) {
    const found = findChild(child,condition);
    // If found,then add this node to the ancestors of the result
    if (found) return Object.assign({},obj,{ children: [found] });
 }
}
var search = { label: 'sofa' };
console.log(findChild(input,search)); // It returns only the first matched item path,i would like to get all matched items path

解决方法

这看起来可以做到:

const filterDeep = (pred) => (xs,kids) =>
  xs .flatMap (
    x => 
      pred (x)
        ? [x]
      : (kids = filterDeep (pred) (x .children || [])) && kids.length
        ? [{... x,children: kids}] 
      : []
    
  )

const testIncludes = (condition) => (obj) =>
  Object .entries (condition) .every (
    ([k,v]) => (obj [k] || '') .toLowerCase () .includes (v .toLowerCase ())
  )

const filterMatches = (obj,conditions) =>
  filterDeep (testIncludes (conditions)) (obj)


const input = [{label: "Home",key: "home",level: 1,children: [{label: "Indoor Furniture",key: "furniture",level: 2,children: [{label: "Chair",key: "chair",level: 3},{label: "Table",key: "table",{label: "Lamp",key: "lamp",level: 3}]}]},{label: "Outdoor",key: "outdoor",children: [{label: "Outdoor Furniture",children: [{label: "Trampoline",key: "trampoline",{label: "Swing",key: "swing",{label: "Large sofa",key: "large sofa",{label: "Medium Sofa",key: "mediumSofa",{label: "Small Sofa Wooden",key: "smallSofaWooden",level: 3}]},{label: "Games",key: "games",children: []}]},{label: "Refurbrished Items",key: "refurbrished items",children: []},{label: "Indoor",key: "indoor",children: [{label: "Electicity",key: "electicity",{label: "Living Room Sofa",key: "livingRoomSofa",children: []}]}]


console .log ('sofa:',filterMatches (input,{label: 'sofa'}))
console .log ('furniture:',{label: 'furniture'}))
.as-console-wrapper {max-height: 100% !important; top: 0}

我们分离出递归过滤机制以及对象匹配部分,将它们放回到filterMatches中。这个想法是,我们可能希望通过多种方式进行过滤,因此该函数采用可以测试当前节点的任意谓词函数。 testIncludes接受键值对的对象,并返回接受对象的函数,并报告该对象的对应键是否每个都包含相关值。 (我根据您的输入/请求的输出组合在此处添加了不区分大小写的检查。)

请注意,我用单词filter而不是find来命名中央函数,因为find通常意味着返回第一个匹配项,而filter应该返回所有匹配项。


对于我自己的用途,我将主要功能的结构略有不同:

const filterMatches = (conditions) => (obj) =>
  filterDeep (testIncludes (conditions)) (obj)

console .log ('sofa:',filterMatches ({label: 'sofa'}) (input))

我非常喜欢这些咖喱函数,按照这种顺序的参数,我觉得它们最有用。但是YMMV。

更新

一条评论指出主要功能出现了皮棉故障。这是可以理解的,因为在条件表达式中使用赋值确实有些棘手。所以这是一些可行的变体:

  • 将分配移动到默认参数:

    const filterDeep = (pred) => (xs,kids) =>
      xs .flatMap (
        (x,_,__,kids = filterDeep (pred) (x .children || [])) => 
          pred (x)
            ? [x]
          : kids.length
            ? [{... x,children: kids}] 
          : [] 
      )
    

    优点:

    • 这使我们的仅表达式样式保持活力,并避免了上面的棘手问题。
    • 这很容易阅读

    缺点:

    • 它使用默认参数,但有问题。
    • 这需要从flatMat命名两个未使用的参数(这里___。)
  • 使用语句样式:

    const filterDeep = (pred) => (xs,kids) =>
      xs .flatMap ((x) => {
        if (pred (x)) {
          return [x]
        }
        const kids = filterDeep (pred) (x .children || [])
        if (kids.length > 0) {
          return [{... x,children: kids}] 
        }
        return []
      })
    

    优点:

    • 不再有任何麻烦
    • 更适合初学者使用

    缺点:

    • ifreturn语句,与使用纯表达式相比,语句导致的模块化代码更少。

    • 使用call助手功能:

    const call = (fn,...args) => fn (...args)
    
    const filterDeep = (pred) => (xs,kids) =>
      xs .flatMap (
        (x) => 
          pred (x)
            ? [x]
          : call (
            (kids) => kids.length ? [{... x,children: kids}] : [],filterDeep (pred) (x .children || [])
          )
      )
    

    优点:

    • call辅助功能非常有用,可以在许多地方重复使用。
    • 它避免了对参数的摆弄

    缺点:

    • 这将真正的三部分测试(返回[x],返回[{... x,children: kids}]和返回[]的最后两个子句组合成一个函数

我对最后一个版本有些偏爱。但是他们中的任何一个都可以。

,

也许这足够了:

const findTerm = (arr,term) => arr.filter(e => JSON.stringify(e).indexOf(term) >= 0)

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。