javascript 如何从键和值中获取javascript对象的路径

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/25403781/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-28 04:28:24  来源:igfitidea点击:

How to get the path from javascript object from key and value

javascriptobject

提问by Dimitri Kopriwa

I have a javascript object width depth.

我有一个 javascript 对象宽度深度。

I need to know the exact path from this key within the object ex: "obj1.obj2.data1"

我需要知道对象中此键的确切路径,例如:“obj1.obj2.data1”

I already know the key is data1, the value is 123.

我已经知道key是data1,value是123。

My javascript object look like this

我的 javascript 对象看起来像这样

{
    obj1: {
        obj2: {
            data1: 213,
            data2: "1231",
            obj3: {
                data: "milf"
            }
        }
    },
    obj4: {
        description: "toto"
    }
}

How could I achieve that ?

我怎么能做到这一点?

here is a jsfiddle : http://jsfiddle.net/3hvav8xf/8/I am trying to implement getPath.

这是一个 jsfiddle:http: //jsfiddle.net/3hvav8xf/8/我正在尝试实现 getPath。

采纳答案by Farkhat Mikhalko

I think recursive function can help to you (Updated version, to check value)

我认为递归函数可以帮助你(更新版本,检查价值)

function path(c, name, v, currentPath, t){
    var currentPath = currentPath || "root";

    for(var i in c){
      if(i == name && c[i] == v){
        t = currentPath;
      }
      else if(typeof c[i] == "object"){
        return path(c[i], name, v, currentPath + "." + i);
      }
    }

    return t + "." + name;
};

path({1: 2, s: 5, 2: {3: {2: {s: 1, p: 2}}}}, "s", 1)

回答by Farkhat Mikhalko

Here you go!

干得好!

function getPath(obj, value, path) {

    if(typeof obj !== 'object') {
        return;
    }

    for(var key in obj) {
        if(obj.hasOwnProperty(key)) {
            console.log(key);
            var t = path;
            var v = obj[key];
            if(!path) {
                path = key;
            }
            else {
                path = path + '.' + key;
            }
            if(v === value) {
                return path;
            }
            else if(typeof v !== 'object'){
                path = t;
            }
            var res = getPath(v, value, path);
            if(res) {
                return res;
            } 
        }
    }

}

getPath(yourObject, valueYouWantToFindPath);

Rerutns path if found, else returns undefined. I have only tested it with objects & comparison is very strict(ie: used ===).

如果找到则返回路径,否则返回未定义。我只用对象测试过它,比较非常严格(即:使用过===)。

Update:Updated version that takes key as an argument.

更新:以 key 作为参数的更新版本。

function getPath(obj, key, value, path) {

    if(typeof obj !== 'object') {
        return;
    }

    for(var k in obj) {
        if(obj.hasOwnProperty(k)) {
            console.log(k);
            var t = path;
            var v = obj[k];
            if(!path) {
                path = k;
            }
            else {
                path = path + '.' + k;
            }
            if(v === value) {
                if(key === k) {
                    return path;
                }
                else {
                    path = t;
                }
            }
            else if(typeof v !== 'object'){
                path = t;
            }
            var res = getPath(v, key, value, path);
            if(res) {
                return res;
            } 
        }
    }

}

getPath(yourObject, key, valueYouWantToFindPath);

回答by Roland Jegorov

The following finds the path in any level of nested objects. Also with arrays. It returns all the paths found, which is something you want if you have keys with the same name.

下面在任何级别的嵌套对象中查找路径。还有数组。它返回找到的所有路径,如果您有同名的键,这是您想要的。

I like this approach because it works with lodashmethods getand setout-of-the-box.

我喜欢这种方法,因为它适用于lodash方法getset开箱即用。

function findPathsToKey(options) {
  let results = [];

  (function findKey({
    key,
    obj,
    pathToKey,
  }) {
    const oldPath = `${pathToKey ? pathToKey + "." : ""}`;
    if (obj.hasOwnProperty(key)) {
      results.push(`${oldPath}${key}`);
      return;
    }

    if (obj !== null && typeof obj === "object" && !Array.isArray(obj)) {
      for (const k in obj) {
        if (obj.hasOwnProperty(k)) {
          if (Array.isArray(obj[k])) {
            for (let j = 0; j < obj[k].length; j++) {
              findKey({
                obj: obj[k][j],
                key,
                pathToKey: `${oldPath}${k}[${j}]`,
              });
            }
          }

          if (obj[k] !== null && typeof obj[k] === "object") {
            findKey({
              obj: obj[k],
              key,
              pathToKey: `${oldPath}${k}`,
            });
          }
        }
      }
    }
  })(options);

  return results;
}

findPathsToKey({ obj: objWithDuplicates, key: "d" })
// ["parentKey.arr[0].c.d", "parentKey.arr[1].c.d", "parentKey.arr[2].c.d"]

Try it here - https://jsfiddle.net/spuhb8v7/1/

在这里试试 - https://jsfiddle.net/spuhb8v7/1/

If you want the result to be a single key (first encountered), you can change the resultsto be a string and if defined, then return the function with it.

如果您希望结果是单个键(第一次遇到),您可以将 the 更改results为字符串,如果已定义,则返回带有它的函数。

回答by David Chriqui

I ended up with the following function, that works with nested objects/arrays :

我最终得到了以下函数,它适用于嵌套对象/数组:

function findPath (obj, name, val, currentPath) {
  currentPath = currentPath || ''

  let matchingPath

  if (!obj || typeof obj !== 'object') return

  if (obj[name] === val) return `${currentPath}['${name}']`

  for (const key of Object.keys(obj)) {
    if (key === name && obj[key] === val) {
      matchingPath = currentPath
    } else {
      matchingPath = findPath(obj[key], name, val, `${currentPath}['${key}']`)
    }

    if (matchingPath) break
  }

  return matchingPath
}

const treeData = [{
  id: 1,
  children: [{
    id: 2
  }]
}, {
  id: 3,
  children: [{
    id: 4,
    children: [{
      id: 5
    }]
  }]
}]

console.log(findPath (treeData, 'id', 5))

回答by Martin

JSON Object can be handled in JavaScript as associative array.

JSON 对象可以在 JavaScript 中作为关联数组进行处理。

So You can cycle through and store indexes of "parents" in some variables.

因此,您可以在某些变量中循环并存储“父母”的索引。

Assume the whole object to be stored in variable called obj.

假设将整个对象存储在名为 obj 的变量中。

for( var p1 in obj )

{

   for( var p2 in obj[ p1 ] )
   {
       for( var p3 in obj[ p1 ][ p2 ] )
       {
           // obj[ p1 ][ p2 ][ p3 ] is current node
           // so for Your example it is obj.obj1.obj2.data1
       }
   }

}

for(var p1 in obj )

{

   for( var p2 in obj[ p1 ] )
   {
       for( var p3 in obj[ p1 ][ p2 ] )
       {
           // obj[ p1 ][ p2 ][ p3 ] is current node
           // so for Your example it is obj.obj1.obj2.data1
       }
   }

}

Hope answer was helpful.

希望回答有帮助。

回答by Redu

I would do this job as follows;

我将按如下方式完成这项工作;

Object.prototype.paths = function(root = [], result = {}) {
  var ok = Object.keys(this);
  return ok.reduce((res,key) => { var path = root.concat(key);
                                  typeof this[key] === "object" &&
                                         this[key] !== null ? this[key].paths(path,res)
                                                            : res[this[key]] == 0 || res[this[key]] ? res[this[key]].push(path)
                                                                                                    : res[this[key]] = [path];
                                  return res;
                                },result);
};

var myObj = {
    obj1: {
        obj2: {
            data1: 213,
            data2: "1231",
            obj3: {
                data: "milf"
            }
        }
    },
    obj4: {
        description: "toto",
        cougars: "Jodi",
        category: "milf"
    }
},
value = "milf",
milfPath = myObj.paths()[value]; // the value can be set dynamically and if exists it's path will be listed.
console.log(milfPath);

A few words of warning:We should be cautious when playing with the Object prototype. Our modification should have the descriptor enumerable = falseor it will list in the for inloops and for instance jQuery will not work. (this is how silly jQuery is, since apparently they are not making a hasOwnPropertycheck in their for in loops) Some good reads are hereand hereSo we have to add this Object method with Object.defineProperty()to make it enumerable = false;. But for the sake of simplicity and to stay in the scope of the question i haven't included that part in the code.

几句警告:我们在使用 Object 原型时应该谨慎。我们的修改应该有描述符,enumerable = false否则它会在for in循环中列出,例如 jQuery 将无法工作。(这就是 jQuery 的愚蠢之处,因为显然他们没有hasOwnProperty检查他们的 for in 循环)这里这里有一些很好的读取所以我们必须添加这个 Object 方法Object.defineProperty()来使它enumerable = false;。但是为了简单起见并保持在问题的范围内,我没有在代码中包含该部分。

回答by Arko Elsenaar

I can highly suggest you to use lodashfor this problem.

我强烈建议你使用lodash来解决这个问题。

In their documentation this should help you out

在他们的文档中,这应该可以帮助您

// using "_.where" callback shorthand
_.find(characters, { 'age': 1 });
// →  { 'name': 'pebbles', 'age': 1, 'blocked': false }