Home > database >  Flattening a JS object
Flattening a JS object

Time:10-20

I have a JS array of objects which looks like:

[{
a : {},
b: {},
c: [{}, {}]
}]

Now I want to flatten this object in such a way, that the array now becomes:

[
  {
    a : {},
    b: {},
    c: {}
  },
  {
    a : {},
    b: {},
    c: {}
  },
]

Note that the array c was flattened, while all the other fields were duplicated across the two objects. What is the best way to do this?

CodePudding user response:

You're going to need a generic function to compute cartesian products and a small zip utility:

/// product([a,b,[c,d]]) => [a,b,c], [a,b,d]

function product(a) {
    let [head = null, ...tail] = a

    if (head === null)
        return [[]]

    if (!Array.isArray(head))
        head = [head]

    return product(tail).flatMap(p =>
        head.map(h => [h, ...p]))
}

/// zip([a,b], [c,d]) => [a,c], [b,d]

function zip(a, b) {
    return a.map((_, i) => [a[i], b[i]]);
}

//

obj = {
    a: 1,
    b: 2,
    c: [3, 4],
    d: [5, 6, 7]
}

for (let p of product(Object.values(obj)))
    console.log(JSON.stringify(
        Object.fromEntries(zip(Object.keys(obj), p))
    ))

CodePudding user response:

This is a perfect use case for Array.flatMap. It iterates over each element in the array and applies a function to it, then replaces that element with the flattened version of the array returned by the function, allowing you to replace the original element with one, zero, or multiple new elements.

Deep cloning is its own can of worms, so I've factored out the cloning function to allow it to be replaced with any given way of cloning. Currently it uses the standard JSON method, but this only works for a subset of possible objects. See the link about deep cloning for more info.

var data = [{
  a : {test:1},
  b: {test:2},
  c: [{test:3}, {test:4}]
}];

data = data.flatMap(obj => {
  //For each value of C in the object, clone the object and replace the clone's C value, then return the array of all clones
  return obj.c.map(cVal => ({...clone(obj), c:cVal}));
});

function clone(obj){
  return JSON.parse(JSON.stringify(obj)); //Clone objects by value (only works for JSON-compatible objects)
}

console.log(data);

  • Related