Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

List all possible paths using lodash

I would like to list all paths of object that lead to leafs

Example:

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

Result:

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

I would like to find simple and readable solution, best using lodash.

like image 983
Paweł Adamski Avatar asked Mar 21 '16 10:03

Paweł Adamski


4 Answers

Here is a solution that uses lodash in as many ways as I can think of:

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

Edit: If you truly want just the leaves, just return result in the last line.

like image 141
Nick Broderick Avatar answered Nov 15 '22 18:11

Nick Broderick


Based on Nick answer, here is a TS / ES6 imports version of the same code

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 || []);
}
like image 33
Sebastien Lorber Avatar answered Nov 15 '22 18:11

Sebastien Lorber


Doesn't use lodash, but here it is with recursion:

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;
}
like image 36
binarymax Avatar answered Nov 15 '22 16:11

binarymax


Feeding that object through this function should do it I think.

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;
}
like image 41
DogPawHat Avatar answered Nov 15 '22 18:11

DogPawHat