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.
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"))
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With