1

I am doing double forEach, but getting a typeError, while trying to reconstruct another object:

const users = [
    {teacher: [
        {file: 'chemistry', size: '2MB'},
        {file: 'math', size: '1MB'}]
    }, {student: [
        {file: 'chemistry', size: '3MB'},
        {file: 'math', size: '4MB'}]
    }
];

let final = {};

users.forEach(function(i) {

    i.forEach(function(j){
        let filesizestring = 'newfilesize'+j.size;
        final[j] = j;
        final.j[j.file] = filesizestring;
    })
})

and the expected result is:

{teacher: {
        chemistry: 'newfilesize2MB',
        math: 'newfilesize1MB'
    }, 
student: {
        chemistry: 'newfilesize3MB',
        math: 'newfilesize4MB'
    }
}

could somebody help me fix this?

update

if nested forEach is not possible, how can i achieve the same result?

4
  • 2
    Cause you dont have a nested array, so you cant use a nested forEach loop. You should definetly change your datastructure, it makes no sense at all. What do you want to do? Commented Jan 22, 2018 at 14:53
  • @JonasW. so how can i achieve this result then? Commented Jan 22, 2018 at 14:54
  • 1
    final.j[j.file] = ... - What should this "thing" do? O.o Commented Jan 22, 2018 at 14:57
  • does the array always conatain only a single object Commented Jan 22, 2018 at 14:57

7 Answers 7

4

You're executing a loop over i -> i.forEach(function(j), however, i is an object, so you need to loop over the objects key-value pairs using for (key in i) and for each key get the array as follow i[key]

const users = [{
  teacher: [{
      file: 'chemistry',
      size: '2MB'
    },
    {
      file: 'math',
      size: '1MB'
    }
  ]
}, {
  student: [{
      file: 'chemistry',
      size: '3MB'
    },
    {
      file: 'math',
      size: '4MB'
    }
  ]
}];

let final = {};

users.forEach(function(i) {
  for (key in i) {
    var obj = {};
    i[key].forEach(function(j) {
      let filesizestring = 'newfilesize' + j.size;
      obj[j.file] = filesizestring;
    });
    final[key] = obj;
  }
});

console.log(final);

Hope it helps!

Sign up to request clarification or add additional context in comments.

6 Comments

can you give an answer with map method?
@moaningalways Why do I have a strange feeling like you are not the one really asking for an answer with a map() method. Is there a reason why you would want a map method?
@JonasW. Why a downvote? Just for the missing explanation? At least can you comment and wait for my update.
Whatever, let's close the conversation!
@JonasW. you're right with that fact, but you can ask for an explanation before hitting a downvote. I do that, have a good day.
|
3

You can do it using reduce like this:

const users = [{
    teacher: [{
            file: 'chemistry',
            size: '2MB'
        },
        {
            file: 'math',
            size: '1MB'
        }
    ]
}, {
    student: [{
            file: 'chemistry',
            size: '3MB'
        },
        {
            file: 'math',
            size: '4MB'
        }
    ]
}];

let final = users.reduce((a, u) => (k = Object.keys(u)[0], { ...a,
    [k]: u[k].reduce((a, s) => ({ ...a,
        [s.file]: 'newfilesize' + s.size
    }), {})
}), {})

console.log(final)

1 Comment

This is a nice way!
1

i is object not array in forEach so you cannot call forEach on object , what you can do is get the array from the object and apply forEach on that array

    const users = [
        {teacher: [{ file: 'chemistry', size: '2MB' },{ file: 'math', size: '1MB' }]}, 
        {student: [{ file: 'chemistry', size: '3MB' },{ file: 'math', size: '4MB' }]}
    ];

    let final = {};

    users.forEach(function (user) {
        let key = Object.keys(user)[0];
        let obj = {};
        user[key].forEach(function(file){
            obj[file.file] = 'newfilesize' + file.size;
        });

        final[key] = obj;
    });

    console.log(final);

1 Comment

the output is not exactly the expected one. could you please modify it? fix it?
1

I just do not like not-having a function, even if it has a silly name.
Otherwise the issue is what appears in other answers too: your top-level variable users is an array, and has forEach. But this array contains objects, which have no forEach, but you can use for in instead (that is supposed to be a link) to get teacher/student. And the last level is again an array, which you can address with forEach.
So there is a nested forEach after all, just it is nested into a for in.

const users = [
    {teacher: [
        {file: 'chemistry', size: '2MB'},
        {file: 'math', size: '1MB'}]
    },
    {student: [
        {file: 'chemistry', size: '3MB'},
        {file: 'math', size: '4MB'}]
    }
];

function magic(coll){
  var res={};
  coll.forEach(function(user){
    for(misc in user){
      user[misc].forEach(function(subject){
        this[subject.file]="newfilesize"+subject.size;
      },res[misc]={});
    }
  });
  return res;
}

console.log(magic(users));

(If someone has a good word for misc, please suggest)

Comments

0

Did you try with a data structure like this instead?

const users = [
    {type: "teacher",
     files: [
        {file: 'chemistry', size: '2MB'},
        {file: 'math', size: '1MB'}]
    }, {type: "student",
        files: [
        {file: 'chemistry', size: '3MB'},
        {file: 'math', size: '4MB'}]
    }
];

let final = {};

users.forEach(function(i) {

    i.files.forEach(function(j){
        let filesizestring = 'newfilesize'+j.size;
        final[j] = j;
        final[j][j.file] = filesizestring;  // <-- What?
    })
})

You'll have to explain the line on which I've put a comment though, I don't get it.

Comments

0

It's not safe to turn an array into an object like that unless you're sure there is only one item in the array. This answer assumes there may be multiple, and so it returns an array containing the structure you want. If you're sure there will only be one you can just use final[0] as the result array would, in that case, only contain a a single element as well.

const users = [{
  teacher: [{
    file: 'chemistry',
    size: '2MB'
  }, {
    file: 'math',
    size: '1MB'
  }]
}, {
  student: [{
    file: 'chemistry',
    size: '3MB'
  }, {
    file: 'math',
    size: '4MB'
  }]
}];

final = [];
users.forEach(i => {
  let obj = {};
  let name = i.teacher ? "teacher" : "student";
  obj[name] = {};
  i[name].forEach(j => obj[name][j.file] = 'newfilesize' + j.size);
  final.push(obj);
});

console.log(final);

Comments

0

I would change the datastructure to this (your current one makes no sense):

  const users = [
   {
     type:"teacher",
     files: [
       {file: 'chemistry', size: '2MB'},
       {file: 'math', size: '1MB'}
     ]
   }, {
     type:"student",
     files: [
       {file: 'chemistry', size: '3MB'},
       {file: 'math', size: '4MB'}
     ]
   }
 ];

Now you can iterate over the users and its files:

for(const user of users){
  for(const file of user.files){
    file.size = "newfilesize" + file.size;
  }
 }

2 Comments

ok, but your answer is still not giving the right output.. could you please fix it?
@moaningalways no i could not. Your expected output makes no sense and is not useful at all.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.