The following object contains a list of recipients and subscriptions, I wish to create a new array with a different structure such as below.
[{"recipientId":"13251376", "services":"3218143,15656200,3721"},{"recipientId":"13251316", "services":"3218143"}
let serviceSubscriptions = [{"recipientId":"13251316","serviceId":"3218143"},{"recipientId":"13251376","serviceId":"3218143"},{"recipientId":"13251376","serviceId":"15656200"},{"recipientId":"13251376","serviceId":"3721"}]
let testArr = [];
serviceSubscriptions.forEach(serviceSubscriptions => {
for (const [key, value] of Object.entries(serviceSubscriptions)) {
//console.log(`${key}: ${value}`);
testArr.push(`${key}:${value}`);
}
});
console.log(testArr);
Here is a list of things I've tried - https://jsfiddle.net/v5azdysg/2/
CodePudding user response:
You can reduce each item into a Map<String, Set<String>>
. After you have the map, you can map the entries to objects where you join the serviceId
arrays.
const serviceSubscriptions = [
{ "recipientId": "13251316", "serviceId": "3218143" },
{ "recipientId": "13251376", "serviceId": "3218143" },
{ "recipientId": "13251376", "serviceId": "15656200" },
{ "recipientId": "13251376", "serviceId": "3721" }
];
const testArr = [
...serviceSubscriptions
.reduce((acc, { recipientId, serviceId }) =>
acc.set(recipientId,
(acc.get(recipientId) ?? new Set).add(serviceId)), new Map)
.entries()
]
.map(([recipientId, serviceIds]) => ({
recipientId,
services: [...serviceIds].join(',')
}));
console.log(testArr);
.as-console-wrapper { top: 0; max-height: 100% !important; }
Here is an alternative version that uses Object
and Array
types instead of Map
and Set
types.
Note: This performs worse than the version above, because it uses spreading which mutates the accumulator and service array values. This should be avoided.
const serviceSubscriptions = [
{ "recipientId": "13251316", "serviceId": "3218143" },
{ "recipientId": "13251376", "serviceId": "3218143" },
{ "recipientId": "13251376", "serviceId": "15656200" },
{ "recipientId": "13251376", "serviceId": "3721" }
];
const testArr = Object
.entries(serviceSubscriptions
.reduce((acc, { recipientId, serviceId }) => ({
...acc,
[recipientId]: [...(acc[recipientId] ?? []), serviceId]
}), {}))
.map(([recipientId, serviceIds]) => ({
recipientId,
services: serviceIds.join(',')
}));
console.log(testArr);
.as-console-wrapper { top: 0; max-height: 100% !important; }
CodePudding user response:
There are many ways to solve this, Mr. Polywhirl's answer is more elegant than the following (I haven't done the O() calc on it to determine efficiency vs this one), but a basic solution just needs to use a couple for loops.
One to get the elements, another to check the testArr to see if we already handled the recipient and another to iterate over the array again starting from the next index to add the subscription ids.
let serviceSubscriptions = [{"recipientId":"13251316","serviceId":"3218143"},{"recipientId":"13251376","serviceId":"3218143"},{"recipientId":"13251376","serviceId":"15656200"},{"recipientId":"13251376","serviceId":"3721"}]
let testArr = [];
for(let i = 0; i < serviceSubscriptions.length; i ) {
// Create a new object so we don't alter the original.
const recipSub = Object.assign({}, serviceSubscriptions[i]);
if (testArr.filter(r => r.recipientId === recipSub.recipientId).length > 0) continue;
for (let y = i 1; y < serviceSubscriptions.length; y ) {
if (serviceSubscriptions[y].recipientId === recipSub.recipientId) {
recipSub.serviceId = recipSub.serviceId ',' serviceSubscriptions[y].serviceId;
}
}
testArr.push(recipSub);
}
console.log(testArr);
console.log(serviceSubscriptions);