使用lodash列出所有可能的路径

时间:2016-03-21 10:12:43

标签: javascript lodash

我想列出导致叶子的所有对象路径

示例:

var obj = {
 a:"1",
 b:{
  foo:"2",
  bar:3
 },
 c:[0,1]
}

结果:

"a","b.foo","b.bar", "c[0]","c[1]"

我想找到简单易读的解决方案,最好使用lodash。

6 个答案:

答案 0 :(得分:5)

这是一个使用lodash的解决方案,我想到的方法很多:

function paths(obj, parentKey) {
  var result;
  if (_.isArray(obj)) {
    var idx = 0;
    result = _.flatMap(obj, function (obj) {
      return paths(obj, (parentKey || '') + '[' + idx++ + ']');
    });
  }
  else if (_.isPlainObject(obj)) {
    result = _.flatMap(_.keys(obj), function (key) {
      return _.map(paths(obj[key], key), function (subkey) {
        return (parentKey ? parentKey + '.' : '') + subkey;
      });
    });
  }
  else {
    result = [];
  }
  return _.concat(result, parentKey || []);
}

编辑:如果你真的只想要叶子,只需在最后一行返回result

答案 1 :(得分:4)

不使用lodash,但这里是递归:

var getLeaves = function(tree) {
    var leaves = [];
    var walk = function(obj,path){
        path = path || "";
        for(var n in obj){
            if (obj.hasOwnProperty(n)) {
                if(typeof obj[n] === "object" || obj[n] instanceof Array) {
                    walk(obj[n],path + "." + n);
                } else {
                    leaves.push(path + "." + n);
                }
            }
        }
    }
    walk(tree,"tree");
    return leaves;
}

答案 2 :(得分:1)

这是我的解决方案。我之所以这样做,是因为我觉得其他解决方案使用了太多的逻辑。我不使用lodash,因为我认为它不会增加任何价值。它也不会使数组键看起来像[0]

const getAllPaths = (() => {
    function iterate(path,current,[key,value]){
        const currentPath = [...path,key];
        if(typeof value === 'object' && value != null){
            return [
                ...current,
                ...iterateObject(value,currentPath) 
            ];
        }
        else {
            return [
                ...current,
                currentPath.join('.')
            ];
        }
    }

    function iterateObject(obj,path = []){
        return Object.entries(obj).reduce(
            iterate.bind(null,path),
            []
        );
    }

    return iterateObject;
})();

如果您需要一个使用[]为键编制索引的密钥,请使用以下命令:

    const getAllPaths = (() => {
        function iterate(path,isArray,current,[key,value]){
            const currentPath = [...path];
            if(isArray){
                currentPath.push(`${currentPath.pop()}[${key}]`);
            }
            else {
                currentPath.push(key);
            }
            if(typeof value === 'object' && value != null){
                return [
                    ...current,
                    ...iterateObject(value,currentPath) 
                ];
            }
            else {
                return [
                    ...current,
                    currentPath.join('.')
                ];
            }
        }

        function iterateObject(obj,path = []){
            return Object.entries(obj).reduce(
                iterate.bind(null,path,Array.isArray(obj)),
                []
            );
        }

        return iterateObject;
    })();

答案 3 :(得分:0)

我认为应该通过这个功能提供该对象。

recursePaths: function(obj){
var result = [];
//get keys for both arrays and objects
var keys = _.map(obj, function(value, index, collection){
    return index;
});


//Iterate over keys
for (var key in keys) {
    //Get paths for sub objects
    if (typeof obj[key] === 'object'){
        var paths = allPaths(obj[key]);
        for (var path in paths){
            result.push(key + "." + path);
        }
    } else {
        result.push(key);
    }
}

return result;
}

答案 4 :(得分:0)

这是我的职责。假定不包含空格的属性名称,它将生成所有可能的点号路径

function getAllPathes(dataObj) {
    const reducer = (aggregator, val, key) => {
        let paths = [key];
        if(_.isObject(val)) {
            paths = _.reduce(val, reducer, []);
            paths = _.map(paths, path => key + '.' + path);
        }
        aggregator.push(...paths);
        return aggregator;
    };
    const arrayIndexRegEx = /\.(\d+)/gi;
    let paths = _.reduce(dataObj, reducer, []);
    paths = _.map(paths, path => path.replace(arrayIndexRegEx, '[$1]'));

    return paths;
}

答案 5 :(得分:0)

基于Nick的答案,这是相同代码的TS / ES6导入版本

import {isArray,flatMap,map,keys,isPlainObject,concat} from "lodash";

// See https://stackoverflow.com/a/36490174/82609
export function paths(obj: any, parentKey?: string): string[] {
  var result: string[];
  if (isArray(obj)) {
    var idx = 0;
    result = flatMap(obj, function(obj: any) {
      return paths(obj, (parentKey || '') + '[' + idx++ + ']');
    });
  } else if (isPlainObject(obj)) {
    result = flatMap(keys(obj), function(key) {
      return map(paths(obj[key], key), function(subkey) {
        return (parentKey ? parentKey + '.' : '') + subkey;
      });
    });
  } else {
    result = [];
  }
  return concat(result, parentKey || []);
}