Sandeep Gupta
Sandeep Gupta

Reputation: 7250

Cleanest way to convert JavaScript object to multi-dimensional array

I am having an array of object (rawData). Each object of this array represents a x-coordinate and y-coordinates of various series (i.e,rawData = [(xi,y1i,y2i,..yni)]). I want to convert it to convertedData, which is an array of the object where each object represents just one series (i.e, convertedData = [[(xi,y1i)], [(xi,y2i)]...[(xi,yni)]])

rawData = [{
    x: 1,
    y1:"1 y1 string", 
    y2:"1 y2 string",
    y3:"1 y3 string",

    yn:"1 yn string",
},{
    x: 2,
    y1:"2 y1 string", 
    y2:"2 y2 string",
    y3:"2 y3 string",

    yn:"2 yn string",
}];

  convertedData = [
    {
      name:"y1",
      data:[
        [1,"1 y1 string"],
        [2,"2 y1 string"],
      ]
    },{
      name:"y2",
      data:[
        [1,"1 y2 string"],
        [2,"2 y2 string"],
      ]
    },{
      name:"y3",
      data:[
        [1,"1 y3 string"],
        [2,"2 y3 string"],
      ]
    },{
      name:"yn",
      data:[
        [1,"1 yn string"],
        [2,"2 yn string"],
      ]
    }
  ];

What is the Javascript way to cleanly attempt this?


Work done by me:

let convertedData = [];
rawData = [{
    x: 1,
    y1:"1 y1 string",
    y2:"1 y2 string",
    y3:"1 y3 string",

    yn:"1 yn string",
},{
    x: 2,
    y1:"2 y1 string",
    y2:"2 y2 string",
    y3:"2 y3 string",

    yn:"2 yn string",
}];

function findDataByName(convertedData, name){
    for (let i=0; i<convertedData.length;++i){
        if(convertedData[i].name === name)
            return convertedData[i].data;
    }
    return temp;
}

function convert() {
    /*initialize the convertedData*/
    Object.keys(rawData[0]).forEach((value)=>{
        if(value==='x') return;
        convertedData.push({
            name:value,//y1
            data:[]//[(xi,y1i)]
        })
    });

    /*now loop over rawData and fill convertedData's data array*/
    rawData.forEach((obj)=>{
        Object.keys(obj).forEach((key)=>{
            if(key==='x') return;
            let data = findDataByName(convertedData,key);
            data.push([obj['x'], obj[key]]);//pushing a new coordinate
        });
    })
}

convert();
console.log(convertedData);

Upvotes: 1

Views: 70

Answers (3)

Aidan Hoolachan
Aidan Hoolachan

Reputation: 2379

It's not beautiful but it does do the trick. The only really janky part is the Number(item[1][0]) which would strip 1 from ["y2", "1 y2 string"]

//Flatten the data
const y = rawData.map(item => {
  return Object.entries(item).filter(entry => entry[0] !== 'x');
}).reduce((acc, curr) => acc.concat(curr), []);

//Create yheader array: ["y1", "y2"..., "yn"];
const yHeaders = [... new Set(y.map(item => item[0]))];

//for each y header, build the corresponding data object 
const clean = yHeaders.map(targetHeader => {
  return {
    name: targetHeader,
    data: y.filter(item => item[0] === targetHeader).map(item => [ Number(item[1][0]), item])
  }
});

Upvotes: 0

Mark
Mark

Reputation: 92440

This is a pretty good use case of reduce on the outer array followed by looping over the entries of each object.

let rawData = [{x: 1,y1:"1 y1 string", y2:"1 y2 string",y3:"1 y3 string",yn:"1 yn string",},{x: 2,y1:"2 y1 string", y2:"2 y2 string",y3:"2 y3 string",yn:"2 yn string",}];

let obj = rawData.reduce((o, item) => {
    Object.entries(item).forEach(([key, val]) => {
        if (key === 'x') return
        if (o.hasOwnProperty(key)){
            let data = o[key].data
            data.push([data.length+1, val])
        } else {
            o[key] = {name: key, data: [[1, val]]}
        }
    })
    return o
}, {})

// obj is an object, but you are only interested in the values:
console.log(Object.values(obj))

Upvotes: 1

trincot
trincot

Reputation: 350270

It all depends on what you would regard cleanest. There are several programming strategies, each with their pros and cons.

Here is a functional programming approach, using Array prototype functions and an ES6 Map as temporary hash to group the data by x value.

const rawData = [{x: 1,y1:"1 y1 string",y2:"1 y2 string",y3:"1 y3 string",yn:"1 yn string",},{x: 2,y1:"2 y1 string",y2:"2 y2 string",y3:"2 y3 string", yn:"2 yn string", }];

const convertedData = Array.from(rawData.reduce( 
    (map, obj) => Object.keys(obj).filter(key => key != "x").reduce(
        (map, key) => map.set(key, (map.get(key) || []).concat([[obj.x, obj[key]]])),
        map
    ),
    new Map
), ([name, data]) => ({name, data}));

console.log(convertedData);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Upvotes: 1

Related Questions