遍历嵌套数组并转换为对象

Looping through nested arrays and converting to objects

我想使用从嵌套数组中收集的信息将一组嵌套数组转换为对象数组:

之前:

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

提前致谢。

如何修复代码

你只需要 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 to iterate the outer array and 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);

你的代码有什么问题:

第三级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));

备选方案:

您可以将 map employeeData 数组转换成一个新数组,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);

您可能只想对外部数组中的每组值使用 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);

问题出在您对变量 x 和 y 的使用

一方面,这条线

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

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

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

,则可以完全消除变量

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

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

其他人已经指出 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));

如果您正确使用索引,可以像您尝试的那样使用 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));

使用 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)

这很容易在一行中完成。 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)

干杯