【问题标题】:Dynamically traverse an object of unknown depth's keys动态遍历未知深度的对象的键
【发布时间】:2020-03-28 18:03:12
【问题描述】:

我有一个奇怪的问题——可能是一个愚蠢的问题——需要一些解释,所以请多多包涵。基本上,我想知道是否有一种方法可以在不使用递归的情况下在 JavaScript 中遍历未知深度的对象。

例如,假设我有一个未知深度的对象。它可能看起来像这样:

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

或者可能是这样的:

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 }
  }
}

obj 也可能更深。我不会提前知道它的深度。

让我们进一步假设我将有一个看起来像这样的arr,并且长度与obj 的深度相匹配。

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

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

我将创建一个循环,在其中生成 1,000 个 arrs,然后我将使用这些循环将 1 添加到未知深度的 obj。所有arrs 的长度都相同(2 或3,或更多),并且始终与obj 的深度相匹配。但是深度会发生变化,我想写一个函数来涵盖所有情况。

需要明确的是,我不会遇到深度为 2 的 obj 和长度为 3 的 arr 的情况。深度和长度将始终匹配一次所有 1000 次迭代。

我的问题是这样的。有没有办法遍历obj1 添加到我需要在不使用递归的情况下达到的“最深”键值对的值中?

我可以构建这样的东西吗?

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

虽然我知道我可以使用递归来达到obj 的底部深度,但将1 添加到正确的valuereturn 它,重建obj 作为递归函数继续@ 987654343@,这意味着我每次都必须为每个单个值重建obj,并覆盖我刚刚在上一次迭代上构建的obj,只是将1添加到obj的一部分.只是看起来不好,但也许没关系。

提前谢谢你。

【问题讨论】:

    标签: javascript arrays recursion javascript-objects


    【解决方案1】:

    如果您尝试就地修改对象,则基本上可以使用指针遍历对象到您到达最后一个键的位置,然后设置它。

    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);

    【讨论】:

    • 减少!尤里卡!谢谢!
    【解决方案2】:

    您可以使用.reduce() 来遍历您的对象,累加器在您的遍历中跟踪您当前的对象。当你的 reduce 完成时,它会在你的路径中拥有最内层的嵌套对象,然后你可以使用数组中的最后一个元素作为修改值的键。正如您所说,如果您对简单地改变原始对象感到满意,则无需递归:

    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);

    【讨论】:

    • @Scott 不用担心 ;)
    【解决方案3】:

    在您描述的情况下,您可以使用 reduce 函数安全地访问嵌套对象:

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

    然后你可以用类似的方式访问你想要的 ['male']['short'] 对象:

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

    你可以对对象执行你想要的操作:

    shortMale.basketball += 1
    

    有关 getNestedObject 函数的更多信息,请参阅:https://hackernoon.com/accessing-nested-objects-in-javascript-f02f1bd6387f

    【讨论】:

      【解决方案4】:

      一旦你可以在 JavaScript 中调用文件夹名称,这是一个获取未知大小事物所有部分的公式 Object.entries(yourObject) 这将返回一个包含对象所有数据的数组,因此您可以轻松地遍历它。我将在示例中返回您的数据,以向您展示 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 :)

      【讨论】:

        猜你喜欢
        • 2014-07-06
        • 2018-07-15
        • 1970-01-01
        • 1970-01-01
        • 2012-09-12
        • 1970-01-01
        • 2021-07-07
        • 2012-09-12
        • 2015-11-17
        相关资源
        最近更新 更多