Search code examples
javascriptdatasetjavascript-objects

Flatten a custom dataset JS Object


Given this dataset :

{
  name: "demo",
  trials: 25,
  data: [ 
    {
      query:
        {planner: "RRT", request: "jc", robot: "ur5"},
      metrics:
        {time: [3,4], length: [32, 33]}
    },
    {
      query:
        {planner: "EST", request: "oc"},
      metrics:
        {time: [6, 8, 9], clearance: [0.7, 0.8, 0.9], success: [1, 0, 1]}
    }
  ]
}

Without specifying any keys inside the query and metrics objects, how could I flatten my dataset to achieve this :

[
    {name: "demo", trials: 25, planner: "RRT", robot: "ur5", request: "jc", time: 3, length: 32},
    {name: "demo", trials: 25, planner: "RRT", robot: "ur5", request: "jc", time: 4, length: 33},
    {name: "demo", trials: 25, planner: "EST", request: "oc", time: 6, clearance: 0.7, success: 1},
    {name: "demo", trials: 25, planner: "EST", request: "oc", time: 8, clearance: 0.8, success: 0},
    {name: "demo", trials: 25, planner: "EST", request: "oc", time: 9, clearance: 0.9, success: 1}
]

As this will be integrated within Obervable notebooks, a one liner is preferable but not mandatory.

EDIT

The metrics object will always be an object of the form { attribute: number[] }. The array size, within the same metrics object, are always equal.


Solution

  • Maybe this will work for you:

    const data = {
        name: 'demo',
        trials: 25,
        data: [
            {
                query: { planner: 'RRT', request: 'jc', robot: 'ur5' },
                metrics: { time: [3, 4], length: [32, 33] },
            },
            {
                query: { planner: 'EST', request: 'oc' },
                metrics: {
                    time: [6, 8, 9],
                    clearance: [0.7, 0.8, 0.9],
                    success: [1, 0, 1],
                },
            },
        ],
    };
    
    const transform = (dataSet) => {
        const { data, ...attributes } = dataSet;
        return dataSet.data
            .map((dataChunk) => {
                const metricEntries = Object.entries(dataChunk.metrics);
                return [
                    ...Array(Object.values(dataChunk.metrics)[0].length).keys(),
                ].map((index) => {
                    return {
                        ...attributes,
                        ...dataChunk.query,
                        ...Object.fromEntries(
                            metricEntries.map((entry) => {
                                return [entry[0], entry[1][index]];
                            }),
                        ),
                    };
                });
            })
            .flatMap((x) => {
                return x;
            });
    };
    
    console.log(transform(data));

    If you have any clarifications, please comment.