I have an object that looks like this:
{ role1: ["id1", "id2", "id3"], role2: ["id1", "id2"], role3: ["id2", "id4"] }
I would like to transform this into an array of objects, making the ids the unique identifiers and the roles into arrays, like so:
[
{ id: "id1", roles: ["role1", "role2"] },
{ id: "id2", roles: ["role1", "role2", "role3"] },
{ id: "id3", roles: ["role1"] },
{ id: "id4", roles: ["role3"] },
]
This is how I do it right now, but I'm not sure if there's a better way. It feels like I'm overcomplicating things.
const obj = {
role1: ["id1", "id2", "id3"],
role2: ["id1", "id2"],
role3: ["id2", "id4"]
};
const users = [];
Object.entries(obj).forEach(([key, ids]) => {
ids.forEach(id => {
const user = users.find(x => x.id === id);
if (user) {
user.roles.push(key);
return;
}
users.push({
id,
roles: [key]
});
});
});
console.log(users);
CodePudding user response:
You could probably just transform it into an object like so:
const obj = {
role1: ["id1", "id2", "id3"],
role2: ["id1", "id2"],
role3: ["id2", "id4"]
};
let userDict = {};
Object.entries(obj).forEach(([key, ids]) => {
ids.forEach(id => {
userDict[id] = (userDict[id] || []);
userDict[id].push(key);
});
});
let users = Object.entries(userDict).map(([id, roles]) => ({ id, roles }));
console.log(users);
.as-console-wrapper { max-height: 100% !important; top: auto; }
Or even use reduce
like so:
const obj = {
role1: ["id1", "id2", "id3"],
role2: ["id1", "id2"],
role3: ["id2", "id4"]
};
let userDict = Object.entries(obj).reduce((acc, [role, ids]) => {
ids.forEach(id => {
acc[id] = (acc[id] || []);
acc[id].push(role);
});
return acc;
}, {});
let users = Object.entries(userDict).map(([id, roles]) => ({ id, roles }));
console.log(users);
.as-console-wrapper { max-height: 100% !important; top: auto; }
Either option is more concise and simple than using an array all the way through.
CodePudding user response:
just another version with Lodash library
const obj = {
role1: ["id1", "id2", "id3"],
role2: ["id1", "id2"],
role3: ["id2", "id4"]
};
const users = _.chain(obj)
.entries()
.reduce((accm, [role, ids]) => {
ids.forEach((id) => (accm[id] || (accm[id] = [])).push(role));
return accm;
}, {})
.entries()
.map(([id, roles]) => ({ id, roles }));
CodePudding user response:
The First thing I get all id from that object by using Set (to avoid duplicates) with flat
const obj = {
role1: ["id1", "id2", "id3"],
role2: ["id1", "id2"],
role3: ["id2", "id4"],
};
const objsId = [
...new Set(
Object.values(obj) //[["id1","id2","id3"],["id1","id2"],["id2","id4"]]
.flat() //['id1', 'id2', 'id3', 'id1', 'id2', 'id2', 'id4']
),
];
console.log(objsId); //['id1', 'id2', 'id3', 'id4']
The second thing is creating an object from that array by using Object.fromEntries
Method transforms a list of key-value pairs into an object.
const objsId = ['id1', 'id2', 'id3', 'id4'];
const idRoles = Object.fromEntries(
objsId.map((id) => [id, []]) //[["id1",[]],["id2",[]],["id3",[]],["id4",[]]]
);
console.log(idRoles) //{"id1":[],"id2":[],"id3":[],"id4":[]}
Finally loop over our array objsId
and for each id, loop over your object obj
entries using Object.fromEntries()
with for..of
And if the current id exists in roles, So add affect that role into idRoles
const obj = {
role1: ["id1", "id2", "id3"],
role2: ["id1", "id2"],
role3: ["id2", "id4"],
};
const objsId = ['id1', 'id2', 'id3', 'id4'];
const idRoles = { id1: [], id2: [], id3: [], id4: [] };
for (const id of objsId) {
for (const [role, ids] of Object.entries(obj)) {
if (ids.includes(id)) idRoles[id].push(role);
}
}
console.log(idRoles);
const obj = {
role1: ["id1", "id2", "id3"],
role2: ["id1", "id2"],
role3: ["id2", "id4"],
};
const objsId = [
...new Set(
Object.values(obj) //[["id1","id2","id3"],["id1","id2"],["id2","id4"]]
.flat() //['id1', 'id2', 'id3', 'id1', 'id2', 'id2', 'id4']
),
]; //['id1', 'id2', 'id3', 'id4']
const idRoles = Object.fromEntries(
objsId.map((id) => [id, []]) //[["id1",[]],["id2",[]],["id3",[]],["id4",[]]]
); //{"id1":[],"id2":[],"id3":[],"id4":[]}
for (const id of objsId) {
for (const [role, ids] of Object.entries(obj)) {
if (ids.includes(id)) idRoles[id].push(role);
}
}
const result = [];
for (let [id, roles] of Object.entries(idRoles)) {
result.push({ id, roles });
}
console.log(JSON.stringify(result, null, 4));