user2917823
user2917823

Reputation: 199

Array of objects to array of objects containing arrays

I've got an array of objects:

 var arr = [
    {
        timemark: "2017-03-01",
        db_total: c1,
        db_used: d1,
        hosts: e1,
        items: f1
    },{
        timemark: "2017-03-02",
        db_total: c2,
        db_used: d2,
        hosts: e2,
        items: f2
    },{
        timemark: "2017-03-03",
        db_total: c3,
        db_used: d3,
        hosts: e3,
        items: f3
    },..]

I am struglling how to transform it to another array but with different structure:

var result = [
    {
        topic: "db_total",
        data: [
            {
                x: "2017-03-01",
                y: c1
            },{
                x: "2017-03-02",
                y: c2
            },{
                x: "2017-03-03",
                y: c3
            },...]
    },{
        topic: "db_used",
        data: [
            {
                x: "2017-03-01",
                y: d1
            },{
                x: "2017-03-02",
                y: d2
            },{
                x: "2017-03-03",
                y: d3
            },...]
    },{
        topic: "hosts",
        data: [
            {
                x: "2017-03-01",
                y: e1
            },{
                x: "2017-03-02",
                y: e2
            },{
                x: "2017-03-03",
                y: e3
            },...]
    },{
        topic: "items",
        data: [
            {
                x: "2017-03-01",
                y: f1
            },{
                x: "2017-03-02",
                y: f2
            },{
                x: "2017-03-03",
                y: f3
            },...]
    },...];

I know I have to do something like this:

//convert
var result = [];
for (var i=0; i<arr.length; i++) {
  result[i]=[arr[i].timemark];
}

Which creates array of arrays:

[
    [2017-03-01],
    [2017-03-02],
    [2017-03-03]
]

It is kinda a start after some hours. But I can't find a way how to start creating objects inside the array instead of arrays? Trying to go baby steps :)

but I am really having problems understanding the snippet and probably using wrong syntax can't get it to work.

Could someone explain how to properly use loop in this case?

Upvotes: 1

Views: 472

Answers (5)

Paul
Paul

Reputation: 106

var arr = [{
    timemark: "2017-03-01",
    db_total: 'c1',
    db_used: 'd1',
    hosts: 'e1',
    items: 'f1'
},{
    timemark: "2017-03-02",
    db_total: 'c2',
    db_used: 'd2',
    hosts: 'e2',
    items: 'f2'
},{
    timemark: "2017-03-03",
    db_total: 'c3',
    db_used: 'd3',
    hosts: 'e3',
    items: 'f3'
}];

console.log(_getConvertedArray(arr))

function _getConvertedArray(array){
    var res = [];
    array.forEach(function(obj){
        Object.keys(obj).forEach(function(key){
            res.push({
                topic: key,
                data: _getTopicData(arr, key)
            });
        });
    });

    return res;
}

function _getTopicData(array, topic){
    var res = [];

    array.forEach(function(obj){
        res.push({
            x: obj.timemark,
            y: obj[topic]
        });
    });

    return res;
}

Upvotes: 1

Omri Luzon
Omri Luzon

Reputation: 4214

You can use the Array.prototype's map function to map each element from the array to a different one, conserving the length of the array.

ex:

var result = arr.map(e => ({x: e.timemark, y:db_total}));

var input = [{
        timemark: "2017-03-01",
        db_total: 1,
        db_used: 1,
        hosts: 1,
        items: 1
    },{
        timemark: "2017-03-02",
        db_total: 1,
        db_used: 1,
        hosts: 1,
        items: 1
    },{
        timemark: "2017-03-03",
        db_total: 1,
        db_used: 1,
        hosts: 1,
        items: 1
    }];
var output = [{
  topic:'db_total',
  data: input.map(e=> ({x:e.timemark, y:e.db_total}))
},{
  topic:'db_used',
  data: input.map(e=> ({x:e.timemark, y:e.db_used}))
},{
  topic:'hosts',
  data: input.map(e=> ({x:e.timemark, y:e.hosts}))
},{
  topic:'items',
  data: input.map(e=> ({x:e.timemark, y:e.items}))
}]
console.log(output)

Upvotes: 1

bur&#230;quete
bur&#230;quete

Reputation: 14678

You can do such a logic; mapping for each grouping, and compiling the final result object;

var arr = [
    {
        timemark: "2017-03-01",
        db_total: "c1",
        db_used: "d1",
        hosts: "e1",
        items: "f1"
    },{
        timemark: "2017-03-02",
        db_total: "c2",
        db_used: "d2",
        hosts: "e2",
        items: "f2"
    },{
        timemark: "2017-03-03",
        db_total: "c3",
        db_used: "d3",
        hosts: "e3",
        items: "f3"
    }];

var result = [];
Object.keys(arr[0])
      .filter(field => field != "timemark")
      .forEach(field => result.push(finalObj(field, arr.map(e => xy(e.timemark, e[field])))));

console.log(result);

function xy(x, y) {
     return { x : x, y : y };
}

function finalObj(name, arr) {
     return { topic : name, data : arr };
}

Since you were suggesting you'd have more fields, thus more topics in the final object, if that is the case, I have modified so that the more fields you add, it will automatically show up in the final resulting object. (Except timemark field ofc)

Upvotes: 2

baao
baao

Reputation: 73211

You can use reduce to do that

var arr = [{timemark: "2017-03-01",db_total: 'c1',db_used: 'd1',hosts: 'e1',items: 'f1'}, {timemark: "2017-03-02",db_total: 'c2',db_used: 'd2',hosts: 'e2',items: 'f2'}, {timemark: "2017-03-03",db_total: 'c3',db_used: 'd3',hosts: 'e3',items: 'f3'}];

let res = arr.reduce((a, b) => {
    for (let key in b) {
        if (b.hasOwnProperty(key) && key !== 'timemark' && ! a.find(v => v.topic === key)) {
            a.push({
                topic: key,
                data: arr.map(o => ({
                    x: o.timemark,
                    y: o[key]
                }))
            });
        }
    }
    return a;
}, []);

console.log(res);

Just for the fun of playing with Maps - below would give another resultset as you intended, but dependending on the further use of your data, it might be helpful (and the code for the creation is also much shorter):

var arr = [{timemark: "2017-03-01",db_total: 'c1',db_used: 'd1',hosts: 'e1',items: 'f1'}, {timemark: "2017-03-02",db_total: 'c2',db_used: 'd2',hosts: 'e2',items: 'f2'}, {timemark: "2017-03-03",db_total: 'c3',db_used: 'd3',hosts: 'e3',items: 'f3'}];

let r = arr.reduce((a,b) => {
    for (let key in b) {
        if (b.hasOwnProperty(key) && key !== 'timemark')
            a.set(key, (a.get(key) || [] ).concat({x: b.timemark, y: b[key]}))
    }
    return a;
}, new Map());

console.log(r);

// USAGE 

// get the data array for db_total:
console.log(r.get("db_total"));

// or for hosts:
console.log(r.get("hosts"));

Upvotes: 1

RobG
RobG

Reputation: 147343

As a fairly simple but very specific function, you can create an "empty" result array and fill it in:

var arr = [
    {
        timemark: "2017-03-01",
        db_total: 'c1',
        db_used: 'd1',
        hosts: 'e1',
        items: 'f1'
    },{
        timemark: "2017-03-02",
        db_total: 'c2',
        db_used: 'd2',
        hosts: 'e2',
        items: 'f2'
    },{
        timemark: "2017-03-03",
        db_total: 'c3',
        db_used: 'd3',
        hosts: 'e3',
        items: 'f3'
    }
];


var result = [{topic: "db_total",data: []},
              {topic: "db_used",data: []},
              {topic: "hosts",data: []},
              {topic: "items",data: []}
             ];

arr.forEach(function (obj) {
  result[0].data.push({x:obj.timemark,y: obj.db_total});
  result[1].data.push({x:obj.timemark,y: obj.db_used});
  result[2].data.push({x:obj.timemark,y: obj.hosts});
  result[3].data.push({x:obj.timemark,y: obj.items});
});

console.log(result);

Or you could go for a more general approach that only depends on the timemark property and builds a result from whatever other properties are provided:

var arr = [{
  timemark: "2017-03-01",
  db_total: 'c1',
  db_used: 'd1',
  hosts: 'e1',
  items: 'f1'
}, {
  timemark: "2017-03-02",
  db_total: 'c2',
  db_used: 'd2',
  hosts: 'e2',
  items: 'f2'
}, {
  timemark: "2017-03-03",
  db_total: 'c3',
  db_used: 'd3',
  hosts: 'e3',
  items: 'f3'
}]

// Collect keys but exclude timemark
var keys = Object.keys(arr[0]).filter(function(v) {
  return v != 'timemark';
});

// Build result: loop over every object in arr
var result = arr.reduce(function(result, obj) {
  // Build object to insert into result array
  Object.keys(obj).forEach(function(p) {
    var i = keys.indexOf(p);
    // Create object for key if it's not timemark and doesn't exist
    // And push the data
    if (i != -1) {
      result[i] = result[i] || {topic:p, data:[]};
      result[i].data.push({x:obj.timemark,y:obj[p]});
    }
  })
  return result;
}, []);

console.log(result);

Upvotes: 0

Related Questions