Think of an object array, each of them having certain array properties like versions
, targets
. I want to ungroup objects for each version
and target
.
const myArray = [
{ 'name': 'a', versions: [1, 2], targets: ['server1', 'server2']},
{ 'name': 'b', versions: [], targets: ['server1', 'server2', 'server3']},
{ 'name': 'c', versions: [1], targets: []}
]
Desired output for myArray
above would be:
[
{ 'name': 'a', version: 1, target: 'server1'},
{ 'name': 'a', version: 1, target: 'server2'},
{ 'name': 'a', version: 2, target: 'server1'},
{ 'name': 'a', version: 2, target: 'server2'},
{ 'name': 'b', version: undefined, target: 'server1'},
{ 'name': 'b', version: undefined, target: 'server2'},
{ 'name': 'b', version: undefined, target: 'server3'},
{ 'name': 'c', version: 1, target: undefined},
]
I pondered using nested for
/forEach
loops, but am almost pretty sure there must be a more precise and reasonable way of achieving it built-in es6 functions or so. And that's what I'm asking for.
Think of an object array, each of them having certain array properties like versions
, targets
. I want to ungroup objects for each version
and target
.
const myArray = [
{ 'name': 'a', versions: [1, 2], targets: ['server1', 'server2']},
{ 'name': 'b', versions: [], targets: ['server1', 'server2', 'server3']},
{ 'name': 'c', versions: [1], targets: []}
]
Desired output for myArray
above would be:
[
{ 'name': 'a', version: 1, target: 'server1'},
{ 'name': 'a', version: 1, target: 'server2'},
{ 'name': 'a', version: 2, target: 'server1'},
{ 'name': 'a', version: 2, target: 'server2'},
{ 'name': 'b', version: undefined, target: 'server1'},
{ 'name': 'b', version: undefined, target: 'server2'},
{ 'name': 'b', version: undefined, target: 'server3'},
{ 'name': 'c', version: 1, target: undefined},
]
I pondered using nested for
/forEach
loops, but am almost pretty sure there must be a more precise and reasonable way of achieving it built-in es6 functions or so. And that's what I'm asking for.
for
loop, and it will grow in plexity the more dimensions you have, since the more nested the loops will have to be.
– Terry
Commented
Dec 18, 2019 at 7:39
You could use .flatMap
:
const notEmpty = arr => arr.length ? arr : [undefined];
myArray.flatMap(({ name, versions, targets }) => notEmpty(versions).flatMap(version => notEmpty(targets).map(target => ({ name, version, target }))));
Or with more dimensions, generators get very useful:
function* cartesian(obj, key, ...keys) {
if(!key) {
yield obj;
return;
}
const { [key + "s"]: entries, ...rest } = obj;
for(const entry of (entries.length ? entries : [undefined])) {
yield* cartesian({ [key]: entry, ...rest }, ...keys);
}
}
myArray.flatMap(it => cartesian(it, "version", "target"))
You can use reduce
method:
const result = myArray.reduce((a, {name, versions, targets}) => {
versions.forEach((el, ind) => {
a.push({name, version: versions[ind], target: targets[ind]})
});
targets.forEach((el, ind) => {
a.push({name, version: versions[ind], target: targets[ind]})
});
return a;
}, []);
An example:
const myArray = [
{ 'name': 'a', versions: [1, 2], targets: ['server1', 'server2']},
{ 'name': 'b', versions: [], targets: ['server1', 'server2', 'server3']},
{ 'name': 'c', versions: [1], targets: []}
]
const result = myArray.reduce((a, {name, versions, targets}) => {
versions.forEach((el, ind) => {
a.push({name, version: versions[ind], target: targets[ind]})
});
targets.forEach((el, ind) => {
a.push({name, version: versions[ind], target: targets[ind]})
});
return a;
}, []);
console.log(result);
const myArray = [
{ 'name': 'a', versions: [1, 2], targets: ['server1', 'server2'] },
{ 'name': 'b', versions: [], targets: ['server1', 'server2', 'server3'] },
{ 'name': 'c', versions: [1], targets: [] }
]
const reducer = (acc, current) => {
const { name, versions, targets } = current;
for (let i = 0; i < versions.length; i++) {
acc.push({ name, version: versions[i], target: targets[i] })
}
for (let i = 0; i < targets.length; i++) {
acc.push({ name, version: versions[i], target: targets[i] })
}
return acc;
}
const ungroup = array => array.reduce(reducer, [])
console.log(ungroup(myArray))
We can Un group the objects in the following way
const rows = [
{
"groupId": "ff686b1c-0d83-4e9e-ac0e-edd4ed7a1579",
"clientName": "Apple",
"Id": 110117,
"manageFunds": [
{
"accountId": "eb9e38a8-2e0e-46c2-b50a-fa5c7c18ea53",
"address": {
"address1": "",
"city": "",
"state": "",
"zipcode": "",
"country": ""
}
},
{
"accountId": "eb9e38a8-2e0e-46c2-b50a-fa5c7c18ea54",
"address": {
"address1": "",
"city": "",
"state": "",
"zipcode": "",
"country": ""
}
}
],
"size": 2,
"bulkUploadErrorMessage": ""
},
{
"groupId": "ff686b1c-0d83-4e9e-ac0e-edd4ed7a1589",
"clientName": "Mango",
"Id": 110118,
"manageFunds": [
{
"accountId": "eb9e38a8-2e0e-46c2-b50a-fa5c7c18ea55",
"address": {
"address1": "",
"city": "",
"state": "",
"zipcode": "",
"country": ""
}
},
{
"accountId": "eb9e38a8-2e0e-46c2-b50a-fa5c7c18ea56",
"address": {
"address1": "",
"city": "",
"state": "",
"zipcode": "",
"country": ""
}
}
],
"size": 2,
"bulkUploadErrorMessage": ""
},
{
"groupId": "ff686b1c-0d83-4e9e-ac0e-edd4ed7a1599",
"clientName": "Orange",
"Id": 110119,
"manageFunds": [
{
"accountId": "eb9e38a8-2e0e-46c2-b50a-fa5c7c18ea57",
"address": {
"address1": "",
"city": "",
"state": "",
"zipcode": "",
"country": ""
}
},
{
"accountId": "eb9e38a8-2e0e-46c2-b50a-fa5c7c18ea58",
"address": {
"address1": "",
"city": "",
"state": "",
"zipcode": "",
"country": ""
}
},
{
"accountId": "eb9e38a8-2e0e-46c2-b50a-fa5c7c18ea59",
"address": {
"address1": "",
"city": "",
"state": "",
"zipcode": "",
"country": ""
}
}
],
"size": 3,
"bulkUploadErrorMessage": ""
}
]
const mergeMF = input => {
const initObj = []
input.forEach(rootItem => {
const { Id, clientName, manageFunds } = rootItem
const groupId = rootItem.groupId
manageFunds.forEach(subItem => {
const newSubItem = {
...subItem,
accountId: subItem.accountId,
Id: Id,
clientName: clientName,
groupId: groupId,
}
initObj.push({
checked: false,
data: newSubItem,
isCollapsed: false,
validationErrors: subItem.errorMessages
})
})
})
return initObj
}
console.log(mergeMF(rows))