使用 Javascript 根据深度值过滤嵌套对象

Posted

技术标签:

【中文标题】使用 Javascript 根据深度值过滤嵌套对象【英文标题】:Filter nested object based on deep value with Javascript 【发布时间】:2022-01-20 19:15:57 【问题描述】:

我有这个嵌套对象:

const menus =  
    path: '/actions/step',
    icon: 'fa fa-wine-bottle',
    title: 'Fasi',
    children: [
      
        path: '/actions/step/analysis',
        title: 'Analisi'
      ,
      
        path: '/actions/step/import',
        title: 'Importazione'
      ,
      
        path: '/actions/step/squeeze',
        title: 'Spremitura'
      ,
      
        path: '/actions/step/move',
        title: 'Spostamento'
      ,
      
        path: '/actions/step/splitauto',
        title: 'Travaso Guidato'
      ,
      
        path: '/actions/step/stir',
        title: 'Rimestaggio'
      ,
      
        path: '/actions/step/clarify',
        title: 'Chiarifica'
      ,
      
        path: '/actions/step/stabilization',
        title: 'Stabilizzazione'
      ,
      
        path: '/actions/step/bottling',
        title: 'Imbottigliamento'
      ,
      
        path: '/actions/step/clean',
        title: 'Pulizia'
      ,
      
        path: '/actions/step/clean_close',
        title: 'Pulizia e Chiusura'
      ,
      
        path: '/actions/step/add_product',
        title: 'Aggiunta Prodotto'
      ,
    ]
  ,
  
    path: '/actions',
    icon: 'fa fa-tasks',
    title: 'Azioni',
    children: [
      
        path: '/actions/type',
        title: 'Tipi di Azione'
      ,
      
        path: '/actions/list',
        title: 'Lista delle Azioni'
      ,
      
        path: '/actions/traceability',
        title: 'Tracciabilità'
      
    ]
  ,
   
    path: '/warehouse', 
    icon: 'fa fa-warehouse', 
    title: 'Magazzino',
    children: [
      
        path: '/warehouse/list-warehouse-item',
        title: 'Lista Oggetti',
        children: [
          
            path: '/warehouse/new-warehouse-item',
            title: 'Nuovo Oggetto'
          
        ]
      ,
    ]
  ,
   
    path: '/suppliers', 
    icon: 'fa fa-truck', 
    title: 'Fornitori',
    children: [
      
        path: '/suppliers/list-suppliers',
        title: 'Lista Fornitori',
        children: [
          
            path: '/suppliers/new-supplier',
            title: 'Nuovo Fornitore'
          
        ]
      
    ]
  

我想要实现的是根据路径值过滤嵌套对象。

如果我有/actions/step/import,我想拥有这个:

[ 
    path: '/actions/step',
    icon: 'fa fa-wine-bottle',
    title: 'Fasi'
,

    path: '/actions/step/import',
    title: 'Importazione'
]

或者如果/warehouse/new-warehouse-item 我会:

[ 
    path: '/warehouse', 
    icon: 'fa fa-warehouse', 
    title: 'Magazzino'
,

    path: '/warehouse/list-warehouse-item',
    title: 'Lista Oggetti'
,

    path: '/warehouse/new-warehouse-item',
    title: 'Nuovo Oggetto'
]

我试图做的是像这样过滤,但它不完整(this.$router.history.current.path 包含字符串路径):

menus.filter(menu => 
    if(menu.children)
        return menu.children.some(child => 
            if(child.children)
                return child.children.some(nephew => 
                    return nephew.path === this.$router.history.current.path;
                )
             else 
                return child.path === this.$router.history.current.path;
            
        )
     else 
        return menu.path === this.$router.history.current.path;
    
);

【问题讨论】:

您的意思是要查找给定对象的父对象吗? 是的,创建一个新的清理对象也很好 【参考方案1】:

以下递归代码给出了请求的过滤。 请注意,出于测试目的,我将给定的数据“菜单”包含在一个数组中。

cnt 变量 (int) 用于调试目的并指示递归级别。可以省略。

items 变量(对象数组)是包含对象的初始数组。

目标变量(字符串)是所需的路径。

sol 变量(对象数组)是一个最初为空的数组,将填充通向目标的路径。必须在对 itemFilter 的任何新调用之前清除它

        let cnt = 0 //For debugging only
        const itemFilter= function(items, target, cnt, sol ) 
            cnt += 1
            for( let i = 0; i<items.length; i++) 
                let item = items[i]
                if ( item.path == target) 
                    sol.push(item)
                    //console.log("DEBUG 1 : ", cnt, i, item.path, "Hit")
                    //console.log(sol)
                    return sol
                
                //Otherwise...
                //console.log(cnt, i, item.path, "No hit")
                if (item.children) 
                    itemFilter(item.children, target, cnt, sol)
                    //console.log("DEBUG 2 : ", cnt, i)
                    //console.log(sol)
                    if (sol.length > 0) 
                        sol.push(item)
                        return sol
                    
                
                
        
        
        
        
    console.log("Suggested solution")    
    console.log("--------------------------------------------------------")
        let t = "/actions/step/import"
        console.log("CASE 1 : ", t)
        let filteredItems = []
        itemFilter(menus, t, 0, filteredItems)
        console.log(filteredItems)
        
        console.log("--------------------------------------------------------")
        t = "/warehouse/new-warehouse-item"
        console.log("CASE 2 : ", t)
        filteredItems = []
        itemFilter(menus, t, 0, filteredItems)
        console.log(filteredItems)
        
        console.log("--------------------------------------------------------")
        t = "/UNDEFINEDPATH/anything"
        console.log("CASE 3 : ", t)
        filteredItems = []
        itemFilter(menus, t, 0, filteredItems)
        console.log(filteredItems)




/*This is the console output (without debugging) : 

Suggested solution
--------------------------------------------------------
CASE 1 :  /actions/step/import
[  path: '/actions/step/import', title: 'Importazione' ,
   path: '/actions/step',
    icon: 'fa fa-wine-bottle',
    title: 'Fasi',
    children:
     [ [Object],
       [Object],
       [Object],
       [Object],
       [Object],
       [Object],
       [Object],
       [Object],
       [Object],
       [Object],
       [Object],
       [Object] ]  ]
--------------------------------------------------------
CASE 2 :  /warehouse/new-warehouse-item
[  path: '/warehouse/new-warehouse-item',
    title: 'Nuovo Oggetto' ,
   path: '/warehouse/list-warehouse-item',
    title: 'Lista Oggetti',
    children: [ [Object] ] ,
   path: '/warehouse',
    icon: 'fa fa-warehouse',
    title: 'Magazzino',
    children: [ [Object] ]  ]
--------------------------------------------------------
CASE 3 :  /UNDEFINEDPATH/anything
[]

*/

【讨论】:

【参考方案2】:

基于@Myrer 的出色贡献,为了省略子对象,我将他的脚本编辑如下:

const itemFilter = function(items, target, sol) 
   for(let i = 0; i < items.length; i++) 
      let item = items[i];
      if (item.path === target) 
         const itemToPush = 
            path: item.path,
            title: item.title
         ;

         if(item.icon)
            itemToPush['icon'] = item.icon;
         

         sol.push(itemToPush);
         return sol;
      

      if (item.children) 
         itemFilter(item.children, target, sol);
         if (sol.length > 0) 
            const itemToPush = 
               path: item.path,
               title: item.title
            ;

            if(item.icon)
               itemToPush['icon'] = item.icon;
            

            sol.push(itemToPush);
            return sol;
         
      
   


let t = '/warehouse/new-warehouse-item';
let filteredItems = [];
itemFilter(this.menus, t, filteredItems);
console.log(filteredItems.reverse()); // Reversed the order of the array

// Output:
// [
//     
//         "path": "/warehouse",
//         "title": "Magazzino",
//         "icon": "fa fa-warehouse"
//     ,
//     
//         "path": "/warehouse/list-warehouse-item",
//         "title": "Lista Oggetti"
//     ,
//     
//         "path": "/warehouse/new-warehouse-item",
//         "title": "Nuovo Oggetto"
//     
// ]

【讨论】:

以上是关于使用 Javascript 根据深度值过滤嵌套对象的主要内容,如果未能解决你的问题,请参考以下文章

在 ES6 深度嵌套的对象的 javascript 数组中查找值

HiveQL:如何编写查询以根据嵌套的 JSON 数组值选择和过滤记录

NSPredicate 根据嵌套结构中的属性过滤自定义对象

根据嵌套数组值过滤数组

基于嵌套值的数组过滤对象数组

JavaScript 根据属性值过滤对象数组