【问题标题】:Looping through nested arrays and converting to objects遍历嵌套数组并转换为对象
【发布时间】:2018-05-20 18:56:53
【问题描述】:

我想将一组嵌套数组转换为一个对象数组,其中包含从嵌套数组中收集的信息:

之前:

var employeeData = [
  [
    ['firstName', 'Bob'], ['lastName', 'Lob'], ['age', 22], ['role', 'salesperson']
  ],
  [
    ['firstName', 'Mary'], ['lastName', 'Joe'], ['age', 32], ['role', 'director']
  ]
]

之后:

[
  {firstName: 'Bob', lastName: 'Lob', age: 22, role: 'salesperson'},
  {firstName: 'Mary', lastName: 'Joe', age: 32, role: 'director'}
]

这是我为解决这个问题而编写的函数,但我不太清楚循环出错的地方:

    var employeeData = [
      [
        ['firstName', 'Bob'], ['lastName', 'Lob'], ['age', 22], ['role', 'salesperson']
      ],
      [
        ['firstName', 'Mary'], ['lastName', 'Joe'], ['age', 32], ['role', 'director']
      ]
    ]


    function transformData(employeeData) {
      let newObject = {};
      let newArr = [];
  
      for (var i = 0; i < employeeData.length; i++) { 
        for (var x = 0; x < employeeData[i].length; x++) { 
          for (var y = 0; y < employeeData[i][y].length; y++) { 
            newObject[employeeData[i][y][0]] = employeeData[i][y][1];
          } 
        }
        newArr.push(newObject);
        newObject = {};
      }
      return newArr;
    }
    
    console.log(transformData(employeeData));

提前致谢。

【问题讨论】:

  • "我看不出循环哪里出错了" 我也不能,因为我不知道你的代码产生了什么。你能举例说明你的输出现在是什么样子吗?
  • 我注意到你从不使用变量 x
  • 正如您在编辑问题以包含代码 sn-p 后看到的那样,代码确实有效,您只需使用前两个数组元素,需要扩展它以包含所有数据.

标签: javascript arrays loops multidimensional-array nested-loops


【解决方案1】:

这很容易在一行中完成。 Javascript 有一个专门用于此的功能。

const employeeData = [
  [
    ['firstName', 'Bob'], ['lastName', 'Lob'], ['age', 22], ['role', 'salesperson']
  ],
  [
    ['firstName', 'Mary'], ['lastName', 'Joe'], ['age', 32], ['role', 'director']
  ]
]

const res = employeeData.map(data => Object.fromEntries(data))
console.log(res)

干杯

【讨论】:

    【解决方案2】:

    如何修复您的代码

    您只需要 2 个 for 循环: 1.迭代数组 2.迭代子数组并构造对象

    var employeeData = [[["firstName","Bob"],["lastName","Lob"],["age",22],["role","salesperson"]],[["firstName","Mary"],["lastName","Joe"],["age",32],["role","director"]]]
    
    function transformData(employeeData) {
      let newObject;
      const newArr = [];
    
      for (var i = 0; i < employeeData.length; i++) {
        newObject = {}; // init new object
        for (var x = 0; x < employeeData[i].length; x++) {
            newObject[employeeData[i][x][0]] = employeeData[i][x][1]; // iterate inner arrays and assign properties to object
        }
        newArr.push(newObject);
      }
      return newArr;
    }
    
    console.log(transformData(employeeData));

    另一种选择是结合使用Array#map 迭代外部数组和Array#reduce 从内部数组构造对象:

    const employeeData = [[["firstName","Bob"],["lastName","Lob"],["age",22],["role","salesperson"]],[["firstName","Mary"],["lastName","Joe"],["age",32],["role","director"]]]
    
    const result = employeeData.map((arr) => 
      arr.reduce((o, [key, value]) => (o[key] = value, o), {})
    );
    
    console.log(result);

    【讨论】:

      【解决方案3】:

      这使用 map 和 reduce 更容易实现

      var employeeData = [
        [
         ['firstName', 'Bob'], ['lastName', 'Lob'], ['age', 22], ['role', 'salesperson']
         ],
        [
         ['firstName', 'Mary'], ['lastName', 'Joe'], ['age', 32], ['role', 'director']
        ]
        ]
      
      var d = employeeData.map(
            x=>x.reduce((a,b)=>{a[b[0]]=b[1];return a;},{})
      )
      
      
      console.log(d)
      

      【讨论】:

        【解决方案4】:

        如果您正确使用索引,您所面临的问题可以使用 for 循环来解决,正如您所尝试的那样。 如果你像我一样格式化你的数据,你会看到你的索引有三个级别 [i,x,y];

        例如对于employeeData[0],你应该得到:

        [
            ['firstName', 'Bob'],
            ['lastName', 'Lob'],
            ['age', 22],
            ['role', 'salesperson']
          ]
        

        那么对于employeeData[0][0],你应该得到:

         ['firstName', 'Bob']
        

        对于employeeData[0][0][0],您应该得到:'firstName'

        要访问“Bob”,您需要使用employeeData[0][0][1],并且由于您知道这个内部数组中只有两个元素,因此您不需要循环遍历它。 正如@TallChuck 所建议的那样,您的问题很大一部分源于忘记使用您的 x 索引。

        var employeeData = [
          [
            ['firstName', 'Bob'],
            ['lastName', 'Lob'],
            ['age', 22],
            ['role', 'salesperson']
          ],
          [
            ['firstName', 'Mary'],
            ['lastName', 'Joe'],
            ['age', 32],
            ['role', 'director']
          ]
        ]
        
        
        function transformData(employeeData) {
          let newObject = {};
          let newArr = [];
        
          for (var i = 0; i < employeeData.length; i++) {
            for (var x = 0; x < employeeData[i].length; x++) {
              newObject[employeeData[i][x][0]] = employeeData[i][x][1];
            }
            newArr.push(newObject);
            newObject = {};
          }
          return newArr;
        }
        
        console.log(transformData(employeeData));

        编辑


        如果您注意索引,您还可以制作一些更复杂的解决方案。假设您有以下数据:

        var employeeData = [
          [
            ['firstName', 'Bob', 'weight', '80kg'],
            ['lastName', 'Lob'],
            ['age', 22],
            ['role', 'salesperson']
          ],
          [
            ['firstName', 'Mary', 'eye color', 'green'],
            ['lastName', 'Joe'],
            ['age', 32],
            ['role', 'director']
          ]
        ]
        

        那么我之前给出的解决方案不会直接起作用。但是,如果您仔细观察,您会发现在某些数组中,您的字段名称位于 Y 索引的 0、2 位置。这意味着您的字段名称位于一对位置,而字段值位于奇数位置。因此,您实际上可以通过 y 循环并检查 Y 索引是否可被 2 整除。

        if(y % 2 == 0 ..){}
        

        只有当有一个伴随的奇数值时才这样做

        if(y % 2 == 0 && employeeData[i][x][y+1]){..}
        

        完整代码如下。

        var employeeData = [
          [
            ['firstName', 'Bob', 'weight', '80kg'],
            ['lastName', 'Lob'],
            ['age', 22],
            ['role', 'salesperson']
          ],
          [
            ['firstName', 'Mary', 'eye color', 'green'],
            ['lastName', 'Joe'],
            ['age', 32],
            ['role', 'director']
          ]
        ]
        
        
        function transformData(employeeData) {
          let newObject = {};
          let newArr = [];
        
          for (var i = 0; i < employeeData.length; i++) {
            for (var x = 0; x < employeeData[i].length; x++) {
              for (var y = 0; y < employeeData[i][x].length; y++) {
                if(y % 2 == 0 && employeeData[i][x][y+1]){
                  newObject[employeeData[i][x][y]] = employeeData[i][x][y+1];
                }
              }
            }
            newArr.push(newObject);
            newObject = {};
          }
          return newArr;
        }
        
        console.log(transformData(employeeData));

        【讨论】:

          【解决方案5】:

          您的代码有什么问题:

          第三级for 循环搞砸了。它应该被删除:

          for (var y = 0; y < employeeData[i][x].length; y++) {
          //                                  ^ by the way this should be x not y (not fixing the problem though)
          

          因为第三级数组包含 2 个需要同时使用的元素(作为键值),应该删除它们的 for 循环

          修复:

          for (var i = 0; i < employeeData.length; i++) { 
              for (var x = 0; x < employeeData[i].length; x++) { 
                  newObject[employeeData[i][x][0]] = employeeData[i][x][1];
              }
              newArr.push(newObject);
              newObject = {};
          }
          

          固定代码示例:

          var employeeData = [
            [
              ['firstName', 'Bob'], ['lastName', 'Lob'], ['age', 22], ['role', 'salesperson']
            ],
            [
              ['firstName', 'Mary'], ['lastName', 'Joe'], ['age', 32], ['role', 'director']
            ]
          ]
          
          
          function transformData(employeeData) {
            let newObject = {};
            let newArr = [];
          
            for (var i = 0; i < employeeData.length; i++) { 
              for (var x = 0; x < employeeData[i].length; x++) { 
                  newObject[employeeData[i][x][0]] = employeeData[i][x][1];
              }
              newArr.push(newObject);
              newObject = {};
            }
            return newArr;
          }
          
          console.log(transformData(employeeData));

          替代解决方案:

          您可以将mapemployeeData 数组转换为一个新数组,reduce将每个子数组转换为这样的对象:

          var result = employeeData.map(function(sub) {
              return sub.reduce(function(obj, pair) {
                  obj[ pair[0] ] = pair[1];
                  return obj;
              }, {});
          });
          

          可以使用 ES6 的箭头函数将其缩短为:

          let result = employeeData.map(sub => sub.reduce((obj, pair) => (obj[pair[0]] = pair[1], obj), {}));
          

          示例:

          let employeeData = [
            [
              ['firstName', 'Bob'], ['lastName', 'Lob'], ['age', 22], ['role', 'salesperson']
            ],
            [
              ['firstName', 'Mary'], ['lastName', 'Joe'], ['age', 32], ['role', 'director']
            ]
          ];
          
          let result = employeeData.map(sub => sub.reduce((obj, pair) => (obj[pair[0]] = pair[1], obj), {}));
          
          console.log(result);

          【讨论】:

          • @CarlEdwards MDN 用于逗号运算符的文档:developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/….
          • 谢谢。从来不知道你可以做这样的事情。
          • @ibrahimmahrir 谢谢!为了阐明我推理中的错误,我认为我将这两个元素(例如,first 和 Bob)中的每一个都视为“循环”的东西,这意味着单独工作。只需要第二个 for 循环,因为我想在一次迭代中将这两个键值对作为一个集合处理,而不是每个元素(“first”然后是“Bob”)都有自己的迭代。
          • @knox-flaneur 通常但不一定所有嵌套数组都需要map/reduce。这实际上取决于您要如何处理数据。想象一个像这样的嵌套数组:[ ["knox", "flaneur"], ["ibrahim", "mahrir"]],并且您想更改为["knox flaneur", "ibrahim mahrir"],那么只有mapjoin 一起使用:àrr.map(sub =&gt; sub.join(" "));。如果数组是[ [5, 6, 7], [1, 4, 2] ],并且您想将其转换为[18, 7],那么map/reduce 很有用:arr.map( sub =&gt; sub.reduce((sum, n) =&gt; sum + n, 0) );。看?这真的取决于你想用数据做什么
          • @knox-flaneur 但我说在大多数情况下map/reduce 用于嵌套数组。您 map 数组的元素,对于每个元素,您在它们上使用 reduce,这意味着(它们与数组有关,或者它们是数组,或者它们是其中包含数组的其他类型的对象)。
          【解决方案6】:

          其他人指出使用 map 数组函数可以简化您的任务,这些都是很好的解决方案(比计数循环好得多),但它们并没有解决您实际提出的问题。

          您的代码实际上运行良好,只是您没有提取所有可用的数据。你只有名字和姓氏。通过再添加两行,您可以获得其余数据。此外,甚至不需要第二个循环(它不会伤害您,但实际上并没有帮助,因为您从未在任何地方使用 x 计数器)。

          var employeeData = [
                [
                  ['firstName', 'Bob'], ['lastName', 'Lob'], ['age', 22], ['role', 'salesperson']
                ],
                [
                  ['firstName', 'Mary'], ['lastName', 'Joe'], ['age', 32], ['role', 'director']
                ]
              ]
          
          
              function transformData(employeeData) {
                let newObject = {};
                let newArr = [];
            
                for (var i = 0; i < employeeData.length; i++) { 
          
                    for (var y = 0; y < employeeData[i][y].length; y++) { 
                      newObject[employeeData[i][y][0]] = employeeData[i][y][1];
                      
                      // Now you have to get the next two array elements as well:
                      newObject[employeeData[i][y+1][0]] = employeeData[i][y+1][1];
                      newObject[employeeData[i][y+2][0]] = employeeData[i][y+2][1];            
                    } 
           
                  newArr.push(newObject);
                  newObject = {};
                }
                return newArr;
              }
              
              console.log(transformData(employeeData));

          【讨论】:

          • 这是一个非常特别定制的“修复”,不适用于 4 以外的任何大小的数组
          • @ibrahimmahrir 是的,我是。第二个循环是不必要的,但不影响结果。第三个循环是对的。
          • 问题中的主要问题是for (var y = 0; y &lt; employeeData[i][y].length; y++) 不会产生标准循环,而是检查每个y 的长度而不是之前的级别。你的回答没有解决这个问题,事实上你也有同样的问题。考虑在第二个 for 循环中使用 y &lt; employeeData[i].length
          • @ScottMarcus 你没有更正他的代码,你只是给他一个恰好在单个测试用例中给出正确解决方案的答案,但你的代码工作的原因不是因为它是正确的,这是因为您为测试用例编写了它。如果您使用的任何示例比他给出的示例更长或更短,它都不起作用,因为您的代码没有解决问题
          • @ScottMarcus 你没有回答他的问题,因为你没有解决循环出错的地方
          【解决方案7】:

          问题在于您使用了变量 x 和 y

          一方面,有一条线

          for (var y = 0; y < employeeData[i][y].length; y++)
          

          也许你的意思是改用employeeData[i][x].length,因为你在这里有它,它的行为会很奇怪。

          但是,如果将变量 y 替换为 x(在您的实现中甚至从未使用过),则可以完全消除变量 y

          这是我对您的函数的建议修改:

          function transformData(employeeData) {
            let newObject = {}; 
            let newArr = []; 
          
            for (var i = 0; i < employeeData.length; i++) { 
              for (var x = 0; x < employeeData[i].length; x++) { 
                newObject[employeeData[i][x][0]] = employeeData[i][x][1];
              }   
              newArr.push(newObject);
              newObject = {}; 
            }
            return newArr;
          }
          

          通过这些更改运行您的示例,我得到了正确的输出:

          [
            {
              firstName: 'Bob',
              lastName: 'Lob',
              age: 22,
              role: 'salesperson'
            },
            {
              firstName: 'Mary',
              lastName: 'Joe',
              age: 32,
              role: 'director'
            }
          ]
          

          【讨论】:

          • 其实不是。代码工作得很好,只是没有深入到嵌套数组中。
          • @ScottMarcus 那是因为你的y 循环使用employeeData[i][y] 而不是employeeData[i][x]
          • 这根本不是我的循环,你的结果和解释不正确。
          • @ScottMarcus 啊,对不起,是的,我不小心有[i][y][0],我应该有[i][y][1],如果你试一试,它现在可以正常工作了
          【解决方案8】:

          对于外部数组中的每组值,您可能只想使用Map 而不是Object

          那么就是new Map(data);的一个非常简单的转换。地图已添加到此类数据集的规范中。

          var employeeData = [
            [['firstName', 'Bob'], ['lastName', 'Lob'], ['age', 22], ['role', 'salesperson']],
            [['firstName', 'Mary'], ['lastName', 'Joe'], ['age', 32], ['role', 'director']]
          ];
          
          const res = employeeData.map(a => new Map(a));
          
          for (const m of res) {
           console.log(m.get("firstName"));
          }

          但如果您最终确实想要数组中的Object 类型,那么您可以转换每个Map()

          var employeeData = [
            [['firstName', 'Bob'], ['lastName', 'Lob'], ['age', 22], ['role', 'salesperson']],
            [['firstName', 'Mary'], ['lastName', 'Joe'], ['age', 32], ['role', 'director']]
          ];
          
          const res = employeeData.map(a => new Map(a));
          
          for (const m of res) {
           console.log(m.get("firstName"));
          }
          
          const oRes = res.map(m => Object.assign({}, ...Array.from(m.entries()).map(([k,v]) => ({[k]:v}))));
          
          console.log(oRes);

          【讨论】:

          • @ScottMarcus:你是对的。我将根据要求添加更多信息以从 Map 转到 Object
          • 问题不是关于map。问题是 OP 使用的循环有什么问题。而且,答案是什么都没有。 OP 只是没有提取所有可用的数据。
          • @ScottMarcus:是的,我知道。我只是提供一个替代方案,他可能会或可能不会决定接受作为他损坏代码的解决方案。其他答案已经处理了直接问题。
          • 这不是一个好的答案应该做的。先回答问题,然后提供替代方案。
          • @ScottMarcus:我不认为提问者试图将所有这些都挤进评论中会有所帮助。我们最终会在这里提供帮助。这不是游戏节目。是有实际问题的真人,对问题的不同解决方案可以增强用户的知识。
          猜你喜欢
          • 2020-07-25
          • 1970-01-01
          • 2022-01-14
          • 1970-01-01
          • 2023-01-25
          • 2018-08-28
          • 1970-01-01
          • 1970-01-01
          • 2021-12-28
          相关资源
          最近更新 更多