Reputation: 71
First of all I am a newbie into Javascript, ES6 etc and I come from Java background. I have a complex javascript array structure (example given below), I am trying to convert this array into a map (similar to how Java has, key value pair kind of thing), key being the permission names (e.g KEY-1, KEY-2, KEY-3, KEY-4,KEY-5 with regards to the javascript array example below) while value being the comma separated values of the actual permission. I can achieve it by looping b thru the nested arrays, but loop is what I am trying to avoid here and wanted to do using map()/reduce()/filter()
Here is an example of how the map should contain the data. Since KEY-2 is present in both the arrays, they will be overridden into one (which is perfectly fine)
KEY-1 = ["Roles.Create","Roles.Edit"]
KEY-2 = ["API-Admin.Create","API-Admin.Edit","API-Admin.Read"]
KEY-3 = ["Roles.Create","Roles.Edit"]
KEY-4 = ["Users.Read"]
KEY-5 = ["Roles.Create","Roles.Edit"]
const teamArr = [
{
"name":"Team1",
"accountId":"Billing",
"teamId":"12345",
"permissions": {
"KEY-1": [
"Roles.Create",
"Roles.Edit"
],
"KEY-2": [
"API-Admin.Create",
"API-Admin.Edit",
"API-Admin.Read"
],
"KEY-3": [
"Roles.Create",
"Roles.Edit"
]
}
},
{
"name":"Team2",
"accountId":"Sales",
"teamId":"6789",
"permissions": {
"KEY-4": [
"Users.Read"
],
"KEY-2": [
"API-Admin.Create",
"API-Admin.Edit",
"API-Admin.Read"
],
"KEY-5": [
"Roles.Create",
"Roles.Edit"
]
}
}
]
KEY-1, KEY-2,KEY-3,KEY-4, KEY-5 etc are all dynamically generated, so I CAN NOT hardcode these keys names into my code (like KEY-1, KEY-2 etc.)
I followed this post https://www.freecodecamp.org/news/15-useful-javascript-examples-of-map-reduce-and-filter-74cbbb5e0a1f/ and below is what I tried but I guess, I am struggling to properly use sort()/reduce() properly on a complex javascript array. I would prefer plain Javascript/ES6 solution (no JQuery pls).
const sorted = test.sort((a, b) => a.permissions - b.permissions);
// Using reduce:
dict = sorted.reduce(
(dict, el, index) => (dict[el.permissions] = sorted.length - index, dict),
{}
);
console.log(dict)
Any help here would highly be appreciated. Thanks
Upvotes: 2
Views: 2219
Reputation: 44087
Since you don't need to worry about the other keys/values, you need to firstly create an array of all the permissions
objects. Then you extract the properties from that array, keeping the arrays unique with Sets:
const teamArr = [{"name":"Team1","accountId":"Billing","teamId":"12345","permissions":{"KEY-1":["Roles.Create","Roles.Edit"],"KEY-2":["API-Admin.Create","API-Admin.Edit","API-Admin.Read"],"KEY-3":["Roles.Create","Roles.Edit"]}},{"name":"Team2","accountId":"Sales","teamId":"6789","permissions":{"KEY-4":["Users.Read"],"KEY-2":["API-Admin.Create","API-Admin.Edit","API-Admin.Read"],"KEY-5":["Roles.Create","Roles.Edit"]}}];
const res = teamArr.flatMap(({ permissions }) => Object.entries(permissions)).reduce((a, [k, v]) => ((a[k] = [...new Set(((a[k] = a[k] || []).push(...v), a[k]))], a)), {});
console.log(res);
.as-console-wrapper { max-height: 100% !important; top: auto; }
More verbose version:
const teamArr = [{"name":"Team1","accountId":"Billing","teamId":"12345","permissions":{"KEY-1":["Roles.Create","Roles.Edit"],"KEY-2":["API-Admin.Create","API-Admin.Edit","API-Admin.Read"],"KEY-3":["Roles.Create","Roles.Edit"]}},{"name":"Team2","accountId":"Sales","teamId":"6789","permissions":{"KEY-4":["Users.Read"],"KEY-2":["API-Admin.Create","API-Admin.Edit","API-Admin.Read"],"KEY-5":["Roles.Create","Roles.Edit"]}}];
const permissions = teamArr.map(({ permissions }) => permissions);
const res = permissions.flatMap(Object.entries).reduce((a, [k, v]) => {
a[k] = a[k] || [];
a[k].push(...v);
a[k] = [...new Set(a[k])];
return a;
}, {});
console.log(res);
.as-console-wrapper { max-height: 100% !important; top: auto; }
Upvotes: 2
Reputation: 12990
You can do it with a combination of flatMap
and reduce
(although flatMap
isn't supported on all browsers yet):
const teamArr = [{
"name": "Team1",
"accountId": "Billing",
"teamId": "12345",
"permissions": {
"KEY-1": [
"Roles.Create",
"Roles.Edit"
],
"KEY-2": [
"API-Admin.Create",
"API-Admin.Edit",
"API-Admin.Read"
],
"KEY-3": [
"Roles.Create",
"Roles.Edit"
]
}
},
{
"name": "Team2",
"accountId": "Sales",
"teamId": "6789",
"permissions": {
"KEY-4": [
"Users.Read"
],
"KEY-2": [
"API-Admin.Create",
"API-Admin.Edit",
"API-Admin.Read"
],
"KEY-5": [
"Roles.Create",
"Roles.Edit"
]
}
}
]
const result = teamArr
.flatMap(t => Object.entries(t.permissions))
.reduce((acc, [key, permissions]) => {
acc[key] = acc[key] || [];
acc[key].push(...permissions.filter(p => !acc[key].includes(p)));
return acc;
}, {});
console.log(result);
If the permissions array for a key can be very big, you can also consider using a Set
next to each key in the accumulator.
Upvotes: 2
Reputation: 791
const teamArr = [
{
"name":"Team1",
"accountId":"Billing",
"teamId":"12345",
"permissions": {
"KEY-1": [
"Roles.Create",
"Roles.Edit"
],
"KEY-2": [
"API-Admin.Create",
"API-Admin.Edit",
"API-Admin.Read"
],
"KEY-3": [
"Roles.Create",
"Roles.Edit"
]
}
},
{
"name":"Team2",
"accountId":"Sales",
"teamId":"6789",
"permissions": {
"KEY-4": [
"Users.Read"
],
"KEY-2": [
"API-Admin.Create",
"API-Admin.Edit",
"API-Admin.Read"
],
"KEY-5": [
"Roles.Create",
"Roles.Edit"
]
}
}
];
function extractPermissions(obj) {
const perms = {};
obj.forEach(entry => {
if (!entry['permissions']) {
return;
}
Object.keys(entry.permissions).forEach(key => {
if (!perms[key]) {
perms[key] = [];
}
entry.permissions[key].forEach(value => {
if (!perms[key].some(val => val === value)) {
perms[key].push(value);
}
});
});
});
return perms;
}
console.log(JSON.stringify(extractPermissions(teamArr), null, 2));
Upvotes: 0