简体   繁体   中英

Looping through nested arrays and converting to objects

I want to convert an group of nested arrays into an array of objects with the collected information from the nested arrays:

BEFORE:

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

AFTER:

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

Here is the function I wrote to solve this but I can't quite see where the loop is going wrong:

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

Thanks in advance.

What's wrong with your code:

The third level for loop is messed up. It should be removed:

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

because the third level arrays contain 2 elements that you need to use at the same time (as key-value), the for loop for them should be removed .

Fix:

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 = {};
}

Fixed code example:

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

Alternative solution:

You can map employeeData array into a new array, reduce ing every sub-array into an object like this:

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

Which can be shortened using ES6's arrow functions to:

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

Example:

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

How to fix your code

You only need 2 for loops: 1. iterate the array 2. iterate the sub arrays and construct the object

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

Another option is to use a combination of Array#map to iterate the outer array and Array#reduce to construct an object from the inner arrays:

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

The issue is your use of the variables x and y

For one thing, there's the line

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

Perhaps you meant instead to use employeeData[i][x].length , because as you have it here, it is going to behave very strangely.

However, you can entirely eliminate the variable y if you replace it with x (which, in your implementation is never even used)

Here's my suggested edits to your function:

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

Running your example with these changes I got correct output:

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

The problmem you face can be solved using for loops, as you were trying, if you use your indexes correctly. If you format your data as I did, you will see that there is three levels for your indexes your [i,x,y];

for example for employeeData[0] you should get:

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

then for employeeData[0][0] you should get:

 ['firstName', 'Bob']

and for employeeData[0][0][0] you should get: 'firstName'

To access 'Bob' you would need to employeeData[0][0][1] and since you know that there is only two elements in this inner array you don´t need to loop though it. as @TallChuck suggested great part of your problem stems from forgetting to use your x index.

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

EDIT


You could also make some more complex solutions if you pay attention to your indexes. Say you have the following data:

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

Then the solution I gave before wouldn´t work directly. But if you look closely you will see that in some of the arrays your field names are located in the positions 0, 2 of the Y index. Which means that your field names are in a pair positions and the filed values in the odd positions. So you can actually make a loop through y and just check if the Y index is divisible by 2.

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

And do this only if there is an accompanying odd value thus

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

The full code is below.

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

You may just want to use a Map instead of an Object for each set of values in the outer array.

Then it's a very simple conversion of new Map(data); . Maps were added to the spec for these kinds of datasets.

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

But if you do ultimately want Object types in the array, then you can convert the each 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); 

This is a lot easier to accomplish with map and 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)

This is quite easy to do in a single line. Javascript has a function just for this.

 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)

Cheers

Others have pointed out how the use of the map array function can simplify your task and those are good solutions (much better than counting loops), but they don't address the question you actually asked.

Your code actually works just fine, you just didn't extract all the data that was available to you. You only got the first and last name. By adding two more lines you can get the rest of the data. Also, and the second loop isn't even necessary (it's not hurting you, but it doesn't actually help because you never use the x counter anywhere).

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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