3

I'm consuming JSON data that has a bit of a weird structure for example:

{
    "RESULT": 
    {
        "COLUMNS": ["ID","name","ENABLED","perms","vcenabled","vcvalue","checkenabled","checkvalue","indxenabled","indxvalue"],
        "DATA": [
                    [7,"Site-A", 1, "1,2", 1, 1, 1, 0, 0, 0],
                    [15,"Site-B", 1, "1,2,3,4", 1, 1, 1, 0, 0, 0]
        ]
    },
    "ERROR": 0
}

I would like to create some JavaScript that would restructure this data to proper JSON structures so that the "Column" array values become the keys for the "DATA" array's values. So after a JS process is run the data resembles the following:

[
  {"ID":7,"name":"Site-A","ENABLED":1,"perms":"1,2","vcenabled":1,"vcvalue":1,"checkenabled":1,"checkvalue":1,"indxenabled":1,"indxvalue":1},
  {"ID":15,"name":"Site-B","ENABLED":1,"perms":"1,2","vcenabled":1,"vcvalue":1,"checkenabled":1,"checkvalue":1,"indxenabled":1,"indxvalue":1}

]

What are the JavaScript best practices for accomplishing the JSON restructuring? Could I accomplish this task using a JS framework like JQuery, Foundation JS, ect... ?

punkdata
  • 885
  • 8
  • 15

7 Answers7

5

Using Underscore, it's a one-liner:

var formatted = _.map(orig.RESULT.DATA, _.partial(_.object, orig.RESULT.COLUMNS));

With plain javascript (less elegant but faster), it would be

var formatted = [],
    data = orig.RESULT.DATA,
    cols = orig.RESULT.COLUMNS,
    l = cols.length;
for (var i=0; i<data.length; i++) {
    var d = data[i],
        o = {};
    for (var j=0; j<l; j++)
        o[cols[j]] = d[j];
    formatted.push(o);
}
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
3

you can use underscore Array functions for this task

http://underscorejs.org/#arrays

uusing the object function would be helpful http://underscorejs.org/#object

from the documentation : _.object(list, [values]) Converts arrays into objects. Pass either a single list of [key, value] pairs, or a list of keys, and a list of values ..the example:

_.object(['moe', 'larry', 'curly'], [30, 40, 50]);
 => {moe: 30, larry: 40, curly: 50}

here is the JSfiddle with the solution http://jsfiddle.net/rayweb_on/kxR88/1/

and the code looks like this for this specific scenario.

 var plain = {
"RESULT": 
{
    "COLUMNS": ["ID","name","ENABLED","perms","vcenabled","vcvalue","checkenabled","checkvalue","indxenabled","indxvalue"],
    "DATA": [
                [7,"Site-A", 1, "1,2", 1, 1, 1, 0, 0, 0],
                [15,"Site-B", 1, "1,2,3,4", 1, 1, 1, 0, 0, 0]
    ]
},
"ERROR": 0
},

formatted = [];

_.each(plain.RESULT.DATA, function(value) {
    var tmp = {};
     tmp = _.object(plain.RESULT.COLUMNS,value)
    formatted.push(tmp);
});

 console.log(formatted);
Rayweb_on
  • 3,727
  • 20
  • 24
  • Well, you really should use the *appropriate* [array function](http://underscorejs.org/#map) :-) – Bergi Jun 19 '13 at 16:05
3

newjson is your new object, j is your json,

code is very fast as it caches the legth and don't uses push.

And as it's pure javascript it's faster than all the libraries.

var j={
 "RESULT":{
  "COLUMNS":[
   "ID",
   "name",
   "ENABLED",
   "perms",
   "vcenabled",
   "vcvalue",
   "checkenabled",
   "checkvalue",
   "indxenabled",
   "indxvalue"
  ],
  "DATA":[
   [7,"Site-A", 1, "1,2", 1, 1, 1, 0, 0, 0],
   [15,"Site-B", 1, "1,2,3,4", 1, 1, 1, 0, 0, 0]
  ]
 },
 "ERROR": 0
}

var newjson=[],d=j.RESULT.COLUMNS.length;
for(var a=0,b=j.RESULT.DATA.length;a<b;a++){
 for(var c=0,tmpObj={};c<d;c++){
  tmpObj[j.RESULT.COLUMNS[c]]=j.RESULT.DATA[a][c];
 }
 newjson[a]=tmpObj;
}

console.log(newjson);

based on Bergi's response u can also use the while-- loop.

var orig={
 "RESULT":{
  "COLUMNS":[
   "ID",
   "name",
   "ENABLED",
   "perms",
   "vcenabled",
   "vcvalue",
   "checkenabled",
   "checkvalue",
   "indxenabled",
   "indxvalue"
  ],
  "DATA":[
   [7,"Site-A", 1, "1,2", 1, 1, 1, 0, 0, 0],
   [15,"Site-B", 1, "1,2,3,4", 1, 1, 1, 0, 0, 0]
  ]
 },
 "ERROR": 0
}

var formatted = [],
data = orig.RESULT.DATA,
cols = orig.RESULT.COLUMNS,
l = cols.length,
f = data.length;

while (f--) {
  var d = data[f],
      o = {},
      g = l;
  while (g--) {
    o[cols[g]] = d[g];
  }
  formatted[f] = o;
}
cocco
  • 16,442
  • 7
  • 62
  • 77
  • Why do you think not using push makes it better? Btw, the code is very slow as it does *not* cache the relevant things. – Bergi Jun 19 '13 at 15:46
  • newjson[a]=tmpObj; is faster than newjson.push(tmpObj).and what u wanna cache? – cocco Jun 19 '13 at 15:49
  • OK, if you have the `index` already available that will be better, but there's no relevant distinction between `arr.push(x)` and `arr[arr.length] = x`. See http://stackoverflow.com/q/614126 for detailed analysis - one should use what is clearer to read :-) – Bergi Jun 19 '13 at 15:59
  • http://jsperf.com/reformat-json yeah it depends on browser, anyway good work with caching =) – cocco Jun 19 '13 at 16:01
  • i added now a while-- loop;) – cocco Jun 19 '13 at 16:52
  • Yeah, that might be faster, but it's getting less readable :-) +1 though – Bergi Jun 19 '13 at 19:49
2

Try this using underscorejs.

var plain = {
    "RESULT": 
    {
        "COLUMNS": ["ID","name","ENABLED","perms","vcenabled","vcvalue","checkenabled","checkvalue","indxenabled","indxvalue"],
        "DATA": [
                [7,"Site-A", 1, "1,2", 1, 1, 1, 0, 0, 0],
                [15,"Site-B", 1, "1,2,3,4", 1, 1, 1, 0, 0, 0]
        ]
    },
    "ERROR": 0
}
   , formatted = [];

_.each(plain.RESULT.DATA, function(value) {
    var tmp = {};
    _.each(value, function(parameter, pos) {
        tmp[plain.RESULT.COLUMNS[pos]] = parameter;
    });
    formatted.push(tmp);
});

console.log(formatted);

http://jsfiddle.net/kxR88/

cr0
  • 617
  • 5
  • 17
  • Why do you use slow `each` functions instead of for-loops? The Underscore approach looks different. – Bergi Jun 19 '13 at 16:05
  • Yip, your underscore one-liner looks better. Nice one with the `_.partial`, never used this. – cr0 Jun 19 '13 at 19:49
2

Actually, you could use a combination of Array#map for the array and Array#reduce for the objects with the new properties

var data = { RESULT: { COLUMNS: ["ID", "name", "ENABLED", "perms", "vcenabled", "vcvalue", "checkenabled", "checkvalue", "indxenabled", "indxvalue"], DATA: [[7, "Site-A", 1, "1,2", 1, 1, 1, 0, 0, 0], [15, "Site-B", 1, "1,2,3,4", 1, 1, 1, 0, 0, 0]] }, ERROR: 0 },
    result = data.RESULT.DATA.map(function (a) {
        return a.reduce(function (o, d, i) {
            o[data.RESULT.COLUMNS[i]] = d;
            return o;
        }, {});
    });

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

With ES6, you could use Object.assign with spread syntax ....

Object.assign adds properties to the given object and returns this object.

Spread syntax ... takes an array and insert the elements as parameters to the function.

var data = { RESULT: { COLUMNS: ["ID", "name", "ENABLED", "perms", "vcenabled", "vcvalue", "checkenabled", "checkvalue", "indxenabled", "indxvalue"], DATA: [[7, "Site-A", 1, "1,2", 1, 1, 1, 0, 0, 0], [15, "Site-B", 1, "1,2,3,4", 1, 1, 1, 0, 0, 0]] }, ERROR: 0 },
    result = data.RESULT.DATA.map(a =>
        Object.assign(...data.RESULT.COLUMNS.map((k, i) => ({ [k]: a[i] }))));

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Nina Scholz
  • 376,160
  • 25
  • 347
  • 392
0

Using JQuery:

function jsonToObj(json){
   return jQuery.parseJSON(JSON.stringify(json));
}

For example, after a GET request the server send a complex object

  $.get("/Files/-2", function (rxData, status) {

      var obj = jsonToObj(rxData);
      console.log(obj);
  });

Logged in console, can be explored through Chrome's Web Developer (F12), in my case looks like this:

image showing nested levels

kuky54
  • 1
  • 1
0

By simple JS, your solution would look like this:

var yourObj = {
  "RESULT": {
    "COLUMNS": ["ID","name","ENABLED","perms","vcenabled","vcvalue","checkenabled","checkvalue","indxenabled","indxvalue"],
    "DATA": [
      [7,"Site-A", 1, "1,2", 1, 1, 1, 0, 0, 0],
      [15,"Site-B", 1, "1,2,3,4", 1, 1, 1, 0, 0, 0]
    ]
  },
  "ERROR": 0
}

//Solution

var finalARR = [];

var colLength = yourObj.RESULT.COLUMNS.length;
var dataLength = yourObj.RESULT.DATA.length;

for (var i = 0; i < dataLength; i++) {
  var finalJSON = {};
  for (var j = 0; j < colLength; j++) {
    finalJSON[yourObj.RESULT.COLUMNS[j]] = yourObj.RESULT.DATA[i][j];
  }
  finalARR[i] = finalJSON;
}

console.log(finalARR);
4N335
  • 267
  • 2
  • 29