Reputation: 461
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?
if nested forEach is not possible, how can i achieve the same result?
Upvotes: 1
Views: 125
Reputation: 33726
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!
Upvotes: 4
Reputation: 3879
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)
Upvotes: 3
Reputation: 13195
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)
Upvotes: 1
Reputation: 18592
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);
Upvotes: 1
Reputation: 138267
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;
}
}
Upvotes: 0
Reputation: 23379
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);
Upvotes: 0
Reputation: 4642
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.
Upvotes: 0