Full path of a json object

前端 未结 9 700
忘了有多久
忘了有多久 2021-01-12 06:02

I\'m trying to flatten an object where the keys will be the full path to the leaf node. I can recursively identify which are the leaf nodes but stuck trying to construct the

相关标签:
9条回答
  • 2021-01-12 06:34

    A non fancy approach, internally uses recursion.

    var x = { one:1,two:{three:3},four:{five: 5,six:{seven:7},eight:8},nine:9};
    var res = {};
    var constructResultCurry = function(src){ return constructResult(res,src); }
            
    function constructResult(target, src) {
      if(!src) return;
      target[src.key] = src.val;
    }
            
    function buildPath(key, obj, overAllKey) {
      overAllKey += (overAllKey ? "." : "") + key;
      if(typeof obj[key] != "object") return { key : overAllKey, val : obj[key] };
      Object.keys(obj[key]).forEach(function(keyInner) {
         constructResultCurry(buildPath(keyInner, obj[key], overAllKey));  
      });
    }
            
    Object.keys(x).forEach(function(k){
      constructResultCurry(buildPath(k, x, ""));
    });
    
    console.log(res);

    0 讨论(0)
  • 2021-01-12 06:43

    I find a tiny JavaScript utility to access properties using path. It is called object-path and is an opensource project on GitHub.

    To get attribute from an object:

    objectPath.get(obj, "a.b");
    

    to set attribute:

    objectPath.set(obj, "a.b", value);
    

    to remove an attribute:

    objectPath.del(obj, "a.b");
    

    So easy!!

    0 讨论(0)
  • 2021-01-12 06:47

    Using newest JS features like Object spread and Object.entries it should be pretty easy:

    function flatObj(obj, path = []) {
        let output = {};
    
        Object.entries(obj).forEach(([ key, value ]) => {
            const nextPath = [ ...path, key ];
    
            if (typeof value !== 'object') {
                output[nextPath.join('.')] = value;
    
                return;
            }
    
            output = {
                ...output,
    
                ...flatObj(value, nextPath)
            };
        });
    }
    

    Please note that this code is probably not the most optimal one as it copies the object each time we want to merge it. Treat it more as a gist of what would it look like, rather than a complete and final solution.

    0 讨论(0)
  • 2021-01-12 06:50

    Partial solution : Give the input as a full path to the function and it gives you the respective output

    var obj = {
      one: 1,
      two: {
        three: 3
      },
      four: {
        five: 5,
        six: {
          seven: 7
        },
        eight: 8
      },
      nine: 9
    };
    
    function deepFind(obj, path) {
      var paths = path.split('.')
        , current = obj
        , i;
    
      for (i = 0; i < paths.length; ++i) {
        if (current[paths[i]] == undefined) {
          return undefined;
        } else {
          current = current[paths[i]];
        }
      }
      return current;
    }
    
    console.log(deepFind(obj, 'four.six.seven'))
    
    0 讨论(0)
  • 2021-01-12 06:50

    You can achieve it by using this function:

    const obj = {
      one: 1,
      two: {
        three: 3
      },
      four: {
        five: 5,
        six: {
          seven: 7
        },
        eight: 8
      },
      nine: 9
    }
    
    
    const flatObject = (obj, keyPrefix = null) =>
      Object.entries(obj).reduce((acc, [key, val]) => {
        const nextKey = keyPrefix ? `${keyPrefix}.${key}` : key
    
        if (typeof val !== "object") {
          return {
            ...acc,
            [nextKey]: val
          };
        } else {
          return {
            ...acc,
            ...flatObject(val, nextKey)
          };
        }
    
      }, {});
      
      console.log(flatObject(obj))

    0 讨论(0)
  • 2021-01-12 06:51

    Here is an interative solution using object-scan.

    object-scan is a data processing tool, so the main advantage here is that it would be easy to do further processing or processing while extracting the desired information

    // const objectScan = require('object-scan');
    
    const myData = { one: 1, two: { three: 3 }, four: { five: 5, six: { seven: 7 }, eight: 8 }, nine: 9 };
    
    const flatten = (data) => {
      const entries = objectScan(['**'], {
        rtn: 'entry',
        joined: true,
        filterFn: ({ isLeaf }) => isLeaf
      })(data);
      // could use Object.fromEntries(entries.reverse()) instead
      return entries.reduceRight((p, [k, v]) => {
        p[k] = v;
        return p;
      }, {});
    };
    
    console.log(flatten(myData));
    // => { one: 1, 'two.three': 3, 'four.five': 5, 'four.six.seven': 7, 'four.eight': 8, nine: 9 }
    .as-console-wrapper {max-height: 100% !important; top: 0}
    <script src="https://bundle.run/object-scan@13.7.1"></script>

    Disclaimer: I'm the author of object-scan

    0 讨论(0)
提交回复
热议问题