简体   繁体   English

动态遍历未知深度键的对象

[英]Dynamically traverse an object of unknown depth's keys

I have kind of a strange question -- possibly a stupid question -- that requires some explanation, so please bear with me.我有一个奇怪的问题——可能是一个愚蠢的问题——需要一些解释,所以请耐心等待。 Basically, I'm wondering if there is a way to traverse an object of unknown depth in JavaScript without using recursion.基本上,我想知道是否有一种方法可以在不使用递归的情况下遍历 JavaScript 中未知深度的对象。

For example, let's say I have an object of unknown depth.例如,假设我有一个未知深度的对象。 It can look like this:它看起来像这样:

let obj_depth2 = {
  male:
    { short: 0, tall: 0 },
  female:
    { short: 0, tall: 0 }
  }

or maybe like this:或者像这样:

let obj_depth3 = {
  male: {
    short:
      { basketball: 0, soccer: 0 },
    tall:
      { basketball: 0, soccer: 0 }
  },
  female: {
    short:
      { basketball: 0, soccer: 0 },
    tall:
      { basketball: 0, soccer: 0 }
  }
}

The obj may be deeper as well. obj也可能更深。 I will not know its depth ahead of time.我不会提前知道它的深度。

Let's assume further that I will have an arr that looks something like this, and will match the depth of the obj in length.让我们进一步假设我将有一个看起来像这样的arr ,并且长度与obj的深度相匹配。

let arr_depth2 = ["male", "short"];

or或者

let arr_depth3 = ["male", "tall", "basketball"];

I will have a loop in which I generate, say, 1,000, of these arr s that I will then use to add 1 to the obj of unknown depth.我将有一个循环,在其中生成 1,000 个这些arr ,然后我将使用这些循环将1添加到未知深度的obj中。 All the arr s will be the same length (2 or 3, or more) and will always match the depth of the obj .所有arr的长度都相同(2 或 3,或更多)并且将始终匹配obj的深度。 But the depth will change and I want to write a single function to cover all situations.但是深度会发生变化,我想编写一个函数来涵盖所有情况。

To be clear, I will NOT have a situation where I have an obj of depth 2 and an arr of length 3. The depths and lengths will always match for all 1,000 iterations at a time.需要明确的是,我不会遇到深度为 2 的obj和长度为 3 的arr的情况。深度和长度将始终匹配所有 1,000 次迭代。

My question is this.我的问题是这个。 Is there a way to traverse the obj to add 1 to the value of the "deepest" key-value pair I need to reach without using recursion?有没有办法遍历obj以在不使用递归的情况下将我需要达到的“最深”键值对的值加1

Can I build something like this?我可以建造这样的东西吗?

obj["male"]["short"] += 1;

Although I know I can use recursion to reach the bottom depth of the obj , add 1 to the proper value , and return it, rebuilding the obj as the recursive function continues to return , this means I would have to rebuild the obj for every single value every time and override the obj I would have just built on the previous iteration, just to add 1 to one part of the obj .虽然我知道我可以使用递归来达到深度底部obj ,加1到适当value ,并return它,重建obj的递归函数继续return ,这意味着我将不得不重建obj每单value 并覆盖我刚刚在上一次迭代中构建的obj ,只是将1添加到obj一部分。 It just seems bad, but maybe it doesn't matter.看起来很糟糕,但也许没关系。

Thank you in advance.先感谢您。

You can do this with .reduce() to traverse down your object, where the accumulator keeps track of your current object in your traversal.您可以使用.reduce()来遍历您的对象,累加器在您的遍历中跟踪您当前的对象。 When your reduce is complete, it will have the inner-most nested object in your path, which you can then use the last element in your array as a key to modify the value.当您的reduce 完成时,它将在您的路径中包含最内部的嵌套对象,然后您可以使用数组中的最后一个元素作为键来修改值。 As you said, there is no need for recursion if you're happy with simply mutating the original object:正如您所说,如果您对简单地改变原始对象感到满意,则不需要递归:

 const obj = {male:{short:{basketball:0,soccer:0},tall:{basketball:0,soccer:0}},female:{short:{basketball:0,soccer:0},tall:{basketball:0,soccer:0}}} const arr = ["male", "tall", "basketball"]; const modify = (obj, [...keys]) => { const last_key = keys.pop(); const last_obj = keys.reduce((o, k) => o[k], obj); last_obj[last_key] += 1; } modify(obj, arr); console.log(obj);

If you're trying to modify the object in place, you can essentially use a pointer to traverse the object to the point you get to the last key and then set it.如果您尝试就地修改对象,您基本上可以使用指针遍历对象到到达最后一个键的点,然后设置它。

 const obj_depth3 = { male: { short: { basketball: 0, soccer: 0 }, tall: { basketball: 0, soccer: 0 } }, female: { short: { basketball: 0, soccer: 0 }, tall: { basketball: 0, soccer: 0 } } } const addOneTo = (obj, path) => { const finalProp = path.pop(); const pointer = path.reduce((pointer, key) => pointer[key], obj); pointer[finalProp]++; } addOneTo(obj_depth3, ["male", "short", "soccer"]) console.log(obj_depth3);

You can safely access a nested object in your described case using the reduce function:您可以使用 reduce 函数在您描述的情况下安全地访问嵌套对象:

const getNestedObject = (nestedObj, pathArr) => {
    return pathArr.reduce((obj, key) =>
        (obj && obj[key] !== 'undefined') ? obj[key] : undefined, nestedObj);
}

Then you can access your desired ['male']['short'] object in a similar fashion:然后你可以以类似的方式访问你想要的 ['male']['short'] 对象:

let shortMale = getNestedObject(obj_depth3, ['male', 'short'])

And you can perform your desired operation on the object:您可以对对象执行所需的操作:

shortMale.basketball += 1

For more information on the getNestedObject function, see: https://hackernoon.com/accessing-nested-objects-in-javascript-f02f1bd6387f有关 getNestedObject 函数的更多信息,请参见: https ://hackernoon.com/accessing-nested-objects-in-javascript-f02f1bd6387f

Here's a formula to get all parts of an unknown sized thing once u can call the folder name in JavaScript Object.entries(yourObject) This returns an array of all the data of your object so you can easily iterate through it.这是一个公式,一旦您可以在 JavaScript 中调用文件夹名称,就可以获取未知大小事物的所有部分Object.entries(yourObject)这将返回一个包含对象所有数据的数组,以便您可以轻松地遍历它。 I would return your data in the example to show you how the Object.entries works我会在示例中返回您的数据,以向您展示 Object.entries 的工作原理

 const obj_depth3 = { male: { short: { basketball: 0, soccer: 0 }, tall: { basketball: 0, soccer: 0 } }, female: { short: { basketball: 0, soccer: 0 }, tall: { basketball: 0, soccer: 0 } } } console.log(Object.entries(obj_depth3)); //you might still want to use another console like inspect element's own to see how the array works, but it has all the depth and stuff :)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM