【问题标题】:Full path of a json objectjson 对象的完整路径
【发布时间】:2017-01-25 14:38:58
【问题描述】:

我正在尝试展平一个对象,其中键将是叶节点的完整路径。我可以递归地识别出哪些是叶节点,但在尝试构建整个路径时卡住了。

示例输入:

{ 一:1, 二: { 三:3 }, 四:{ 五:5, 六: { 七:7 }, 八:8 }, 九:9 }

输出:

{ 一:1, '二.三': 3, '四.五':5, '四.六.七':7, '四.八':8, 九:9 }

【问题讨论】:

  • 你可以看到这个答案:stackoverflow.com/questions/19098797/…希望它能帮到你。
  • 你为什么要这个?
  • @Victor 我正在进行 api 调用,例如 api.movi​​estore.com/movies?where[movie.name:eq]=gravity。我需要展平一个对象来构造过滤查询。
  • @Sayem 哦,当然。我以为您只是希望能够通过路径或其他方式获取数据。
  • 这个问题太笼统了,因为有很多可能的解决方案。尝试自己编写代码,如果遇到任何具体问题,请提出来。

标签: javascript algorithm tree


【解决方案1】:

这是使用object-scan 的交互式解决方案。

object-scan 是一种数据处理工具,所以这里的主要优点是可以很容易地进行进一步的处理或在提取所需信息的同时进行处理

// 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(['**'], {
    reverse: false,
    rtn: 'entry',
    joined: true,
    filterFn: ({ isLeaf }) => isLeaf
  })(data);
  return Object.fromEntries(entries);
};

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.8.0"></script>

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

【讨论】:

    【解决方案2】:

    你可以使用这个函数来实现它:

    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))

    【讨论】:

      【解决方案3】:

      您可以使用递归方法并收集对象的键。这个提议也寻找数组。

      function getFlatObject(object) {
          function iter(o, p) {
              if (o && typeof o === 'object') {
                  Object.keys(o).forEach(function (k) {
                      iter(o[k], p.concat(k));
                  });
                  return;
              }
              path[p.join('.')] = o;
          }
      
          var path = {};
          iter(object, []);
          return path;
      }
      
      var obj = { one: 1, two: { three: 3 }, four: { five: 5, six: { seven: 7 }, eight: 8 }, nine: 9 },
          path = getFlatObject(obj);
      	
      console.log(path);

      【讨论】:

        【解决方案4】:

        我找到了一个小型 JavaScript 实用程序来使用路径访问属性。它被称为object-path,是 GitHub 上的一个开源项目。

        从对象中获取属性:

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

        设置属性:

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

        删除一个属性:

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

        这么简单!!

        【讨论】:

          【解决方案5】:

          您可以简单地执行以下操作;

          var obj = {one: 1, two: {three: 3}, four: {five: 5, six: {seven: 7}, eight: 8}, nine: 9},
          flatObj = (o,p="") => { return Object.keys(o)
                                               .map(k => o[k] === null           ||
                                                         typeof o[k] !== "object" ? {[p + (p ? ".":"") + k]:o[k]}
                                                                                  : flatObj(o[k],p + (p ? ".":"") + k))
                                               .reduce((p,c) => Object.assign(p,c));
                                };
          console.log(flatObj(obj));

          【讨论】:

            【解决方案6】:

            一种不花哨的方法,内部使用递归。

            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);

            【讨论】:

              【解决方案7】:

              var obj = {
                one: 1,
                two: {
                  three: 3
                },
                four: {
                  five: 5,
                  six: {
                    seven: 7
                  },
                  eight: 8
                },
                nine: 9
              };
              
              function flatten(obj) {
                var flatObj = {}
              
                function makeFlat(obj, path) {
                  var keys = Object.keys(obj);
                  if (keys.length) {
                    keys.forEach(function (key) {
                      makeFlat(obj[key], (path ? path + "." : path) + key);
                    })
                  } else {
                    flatObj[path] = obj;
                  }
                }
                makeFlat(obj, "");
                return flatObj;
              }
              
              console.log(flatten(obj));

              【讨论】:

                【解决方案8】:

                使用 Object spread 和 Object.entries 等最新的 JS 功能应该很容易:

                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)
                        };
                    });
                }
                

                请注意,这段代码可能不是最优化的,因为每次我们想要合并它时它都会复制对象。更多地将其视为它的外观,而不是完整的最终解决方案。

                【讨论】:

                  【解决方案9】:

                  部分解决方案: 将输入作为函数的完整路径提供,它会为您提供相应的输出

                  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'))
                  

                  【讨论】:

                    猜你喜欢
                    • 1970-01-01
                    • 2011-12-11
                    • 2014-10-29
                    • 1970-01-01
                    • 2016-12-18
                    • 2017-03-19
                    • 1970-01-01
                    • 1970-01-01
                    相关资源
                    最近更新 更多