Create path from javascript object property

2019-08-22 16:17发布

问题:

Let's say I've got the following javascript object

var obj = {
            a:{
                b:"value",
                c:{
                    d:"value2"
                }
            }
        }

What function would, when input with the "d" object (for example, function getPath(obj, d)), output the "a.c.d" string? I've tried various things including object-path, but it doesn't seem to be designed for that

回答1:

You could use an iterative and recursive approach.

function getPath(object, key) {

    function iter(o, p) {
        if (typeof o === 'object') {
            return Object.keys(o).some(function (k) {
                return iter(o[k], p.concat(k));
            });
        }
        if (p[p.length - 1] === key) {
            path = p;
            return true;
        }
    }

    var path = [];
    iter(object, []);
    return path.join('.');
}

console.log(getPath({ d: { d: { d: { d: 'val' } } } }, 'd'));
console.log(getPath({ a: { b: 'value', c: { d: 'value2' } } }, 'd'));
.as-console-wrapper { max-height: 100% !important; top: 0; }



回答2:

I had a fair amount of fun making this one up, it generates a list of every possible path that can be made from the object and returns the longest one ending with the correct key, it returns an empty string of not found:

function getPath(obj, key) {
    paths = []

    function getPaths(obj, path) {
        if (obj instanceof Object && !(obj instanceof Array)) {
            for (var k in obj){
                paths.push(path + "." + k)
                getPaths(obj[k], path + "." + k)
            }
        }
    }

    getPaths(obj, "")
    return paths.map(function(p) {
        return p.slice(p.lastIndexOf(".") + 1) == key ? p.slice(1) : ''
    }).sort(function(a, b) {return b.split(".").length - a.split(".").length;})[0];
}

var obj = { a:{ b:"value", c:{ d:"value2"}}};
console.log(getPath(obj, "b"))
console.log(getPath(obj, "c"))
console.log(getPath(obj, "d"))

var obj = { d:{ d:"value", d:{ d:"value2"}}};
console.log(getPath(obj, "d"))



回答3:

You can iterate over the object using a recursive function, and save the path like :

function getPath(object, keyValue, path) {
  for (var k in object) {
    if (k === keyValue) {
      return path + '.' + k;
    }
    else if (typeof object[k] === 'object') {
      return getPath(object[k], keyValue, path !== '' ? path + '.' + k : k);
    }
  }
}

var obj = {
    a:{
        b:"value",
        c:{
            d:"value2"
        }
    }
};

var path = getPath(obj, 'd', '');
console.log(path);



回答4:

Here you go. The function you want to use is findLongestPath:

var obj = {
    a:{
        b:"value",
        c:{
            d:"value2"
        }
    }
};

function findAllPaths(obj, property, startString = '') {
  var pathStrings = [];
  Object.keys(obj).forEach(key => {
    if(typeof obj[key] === 'object') {
      pathStrings.push(...findAllPaths(obj[key], property, startString + key + '.'));
      return;
    }
    
    pathStrings.push(startString + key);
  });
  
  return pathStrings;
}

function findLongestPath(obj, property) {
  return findAllPaths(obj, property)
    .filter(str => str.split('').reverse().join('').slice(0, property.length) === property.split('').reverse().join(''))
    .reduce((longest, next) => longest.length >= next.length ? longest : next, '');
}

console.log(findLongestPath(obj, 'd'));

findAllPaths is a recursive function that iterates through the object and generates an array of all possible object paths. findLongestPath filters those strings to make sure the last property matches the property given, and then returns the longest of those.