【问题标题】:encode path of nested javascript object嵌套javascript对象的编码路径
【发布时间】:2021-02-07 03:35:12
【问题描述】:

我想编写一个函数,它接受一个嵌套的 json 对象,并在每个表示对象本身的“路径”或层次结构的对象中写入一个 path 数组。 path 数组应该由父节点的id 填充。限制数组对象应该有一个路径,并且由于它们没有 id,因此根据该数组中的索引为它们提供一个枚举键。我的尝试低于但我在某些第 n 级没有得到正确的路径。

let nestedObject = {
    "name":"bob",
    "root_rule":{
       "id":0,
       "limits":[
          {
             "value":0
          }
       ],
       "rules":[
          {
             "id":15,
             "limits":[
                
             ],
             "rules":[
                
             ]
          },
          {
             "id":16,
             "limits":[
                {
                   "value":25000000
                },
                {
                   "value":50001
                },
                {
                   "value":25000001
                }
             ],
             "rules":[
                {
                   "id":20,
                   "limits":[
                      {
                         "value":0
                      }
                   ],
                   "rules":[
                      {
                         "id":21,
                         "limits":[
                            
                         ],
                         "rules":[
                            
                         ]
                      }
                   ]
                }
             ]
          }
       ]
    }
 }
function encodeNestedPath(nestedJson, pathList, type, parent = null) {

    // process rood node
    if ((typeof nestedJson) == 'object') {
        
        if(nestedJson && nestedJson.condition && nestedJson.condition.name === 'ROOT') {
            nestedJson['path'] = [String(nestedJson['id'])];
        }
        
        if(nestedJson.limits) {
            encodeNestedPath(nestedJson.limits, nestedJson['path'], 'limits', nestedJson['id']);
        }
        if(nestedJson.rules) {
            encodeNestedPath(nestedJson.rules, nestedJson['path'], 'rules', nestedJson['id']);
        }
    }

    // traverse children nodes
    if (Array.isArray(nestedJson)) {
        for (const [i, element] of nestedJson.entries()) {

            element['path'] = [];

            if(String(parent)) {
                element['path'].push(String(parent))
            }

            let parentId
            if(!element.hasOwnProperty('id')) {
                element['path'].push(type+'_'+i)
                pathList = null
            } else {
                element['path'].push(String(element['id']))
                parentId = element['id']
            }

            if(element.limits) {
                encodeNestedPath(element.limits, element['path'], 'limits', parentId);
            }
            if(element.rules) {
                encodeNestedPath(element.rules, element['path'], 'rules', parentId);
            }
        }
    }
}



encodeNestedPath(nestedObject['root_rule'], null, null, null)
console.log(JSON.stringify(nestedObject['root_rule'], null, 4))

想要的输出是这样的。

【问题讨论】:

    标签: javascript json recursion tree nested


    【解决方案1】:

    不喜欢重新发明轮子。我建议您使用库作为基础知识。这些天来,我们使用object-scan 进行所有数据处理。一旦您了解如何使用它,它就会很强大。以下是您如何使用它来解决您的问题:

    // const objectScan = require('object-scan');
    
    const process = (data) => objectScan(['**.id', '**.limits[*]'], {
      rtn: 'bool',
      filterFn: ({ value, parents, property }) => {
        const path = parents.filter((p) => 'id' in p).map(({ id }) => id).reverse();
        if (property === 'id') {
          parents[0].path = path;
        } else {
          value.path = path.concat(`limit_${property}`);
        }
      }
    })(data);
    
    const data = { name: 'bob', root_rule: { id: 0, limits: [{ value: 0 }], rules: [{ id: 15, limits: [], rules: [] }, { id: 16, limits: [{ value: 25000000 }, { value: 50001 }, { value: 25000001 }], rules: [{ id: 20, limits: [{ value: 0 }], rules: [{ id: 21, limits: [], rules: [] }] }] }] } };
    
    console.log(process(data)); // returns true iff match
    // => true
    
    console.log(data);
    // => { name: 'bob', root_rule: { id: 0, limits: [ { value: 0, path: [ 0, 'limit_0' ] } ], rules: [ { id: 15, limits: [], rules: [], path: [ 0, 15 ] }, { id: 16, limits: [ { value: 25000000, path: [ 0, 16, 'limit_0' ] }, { value: 50001, path: [ 0, 16, 'limit_1' ] }, { value: 25000001, path: [ 0, 16, 'limit_2' ] } ], rules: [ { id: 20, limits: [ { value: 0, path: [ 0, 16, 20, 'limit_0' ] } ], rules: [ { id: 21, limits: [], rules: [], path: [ 0, 16, 20, 21 ] } ], path: [ 0, 16, 20 ] } ], path: [ 0, 16 ] } ], path: [ 0 ] } }
    .as-console-wrapper {max-height: 100% !important; top: 0}
    <script src="https://bundle.run/object-scan@13.8.0"></script>

    免责声明:我是object-scan的作者

    提供更多控制权的替代方式

    // const objectScan = require('object-scan');
    
    const process = (data) => {
      const extractPath = (parents) => parents
        .filter((p) => 'id' in p)
        .map(({ id }) => id)
        .reverse();
      const logic = {
        '**.id': ({ parents }) => {
          parents[0].path = extractPath(parents);
        },
        '**.limits[*]': ({ value, parents, property }) => {
          value.path = [...extractPath(parents), `limit_${property}`];
        }
      };
      return objectScan(Object.keys(logic), {
        rtn: 'bool',
        filterFn: (kwargs) => kwargs.traversedBy.forEach((n) => logic[n](kwargs))
      })(data);
    };
    
    const data = { name: 'bob', root_rule: { id: 0, limits: [{ value: 0 }], rules: [{ id: 15, limits: [], rules: [] }, { id: 16, limits: [{ value: 25000000 }, { value: 50001 }, { value: 25000001 }], rules: [{ id: 20, limits: [{ value: 0 }], rules: [{ id: 21, limits: [], rules: [] }] }] }] } };
    
    console.log(process(data));
    // => true
    
    console.log(data);
    // => { name: 'bob', root_rule: { id: 0, limits: [ { value: 0, path: [ 0, 'limit_0' ] }, path: [ 0 ] ], rules: [ { id: 15, limits: [], rules: [], path: [ 0, 15 ] }, { id: 16, limits: [ { value: 25000000, path: [ 0, 16, 'limit_0' ] }, { value: 50001, path: [ 0, 16, 'limit_1' ] }, { value: 25000001, path: [ 0, 16, 'limit_2' ] }, path: [ 0, 16 ] ], rules: [ { id: 20, limits: [ { value: 0, path: [ 0, 16, 20, 'limit_0' ] }, path: [ 0, 16, 20 ] ], rules: [ { id: 21, limits: [], rules: [], path: [ 0, 16, 20, 21 ] } ], path: [ 0, 16, 20 ] } ], path: [ 0, 16 ] } ], path: [ 0 ] } }
    .as-console-wrapper {max-height: 100% !important; top: 0}
    <script src="https://bundle.run/object-scan@13.8.0"></script>

    免责声明:我是object-scan的作者

    【讨论】:

      【解决方案2】:

      您的函数中的一个问题是您没有对pathList 参数做任何有用的事情。相反,您从头开始构建路径:

      nestedJson['path'] = [String(nestedJson['id'])];
      

      并与:

      element['path'] = [];
      

      后者后面跟着一个推。

      本质上,您的所有 path 属性都设置为长度为 1 的数组。

      这是一个遍历对象层次结构的实现(不对limitsrules 等硬编码属性进行特殊处理)并应用您描述的逻辑:

      function encodeNestedPath(obj, pathList=[], parentKey) {
          if (Array.isArray(obj)) {
               // remove plural and append underscore
              parentKey = parentKey !== undefined ? parentKey.replace(/s?$/, "_") : "";
              obj.forEach((elem, i) => encodeNestedPath(elem, pathList, parentKey + i));
          } else if (Object(obj) === obj) {
              if ("id" in obj) parentKey = obj.id;
              if (parentKey !== undefined) pathList = pathList.concat(parentKey);
              if (pathList.length) obj.path = pathList
              for (let prop in obj) encodeNestedPath(obj[prop], pathList, prop);
          }
      }
      
      // object from the question:
      let nestedObject = {"name": "bob","root_rule":{"id":0,"limits":[{"value":0}],"rules":[{"id":15,"limits":[],"rules":[]},{"id":16,"limits":[{"value":25000000},{"value":50001},{"value":25000001}],"rules":[{"id":20,"limits":[{"value":0}],"rules":[{"id":21,"limits":[],"rules":[]}]}]}]}};
      
      encodeNestedPath(nestedObject);
      console.log(nestedObject);

      【讨论】:

        猜你喜欢
        • 2015-11-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-01-20
        • 1970-01-01
        • 1970-01-01
        • 2021-11-17
        • 1970-01-01
        相关资源
        最近更新 更多