通过JavaScript迭代复杂的JSON对象的最简单方法

3

我正在使用具有一些奇怪结构的JSON数据,例如:

{
    "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
}

我希望创建一些JavaScript代码,以便将此数据重构为正确的JSON结构,使“Column”数组值成为“DATA”数组值的键。因此,在运行JS处理之后,数据类似于以下内容:
[
  {"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}

]

在进行JSON重构时,JavaScript的最佳实践是什么?我能否使用JS框架如JQuery、Foundation JS等来完成这个任务?


2
你可以通过一个简单的循环来完成这个任务。创建一个空对象,遍历 COLUMNS,从 DATA 中获取数据并填充到新对象中。 - claustrofob
@claustrofob:为了简单起见,请使用两个循环 :-) - Bergi
7个回答

5
使用Underscore,这是一个只需一行代码即可完成的操作:
var formatted = _.map(orig.RESULT.DATA, _.partial(_.object, orig.RESULT.COLUMNS));

用纯JavaScript(不太优雅但更快)实现如下:
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);
}

3
你可以使用下划线数组函数完成此任务。

http://underscorejs.org/#arrays

使用对象函数将会很有帮助 http://underscorejs.org/#object

从文档中得知: _.object(list, [values]) 将数组转换为对象。传递一个键值对的单个列表或者一个键的列表和一个值的列表..例子:

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

这里是解决方案的 JSFiddle 链接http://jsfiddle.net/rayweb_on/kxR88/1/

对于这个特定场景,代码如下。

 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);

嗯,你真的应该使用适当的数组函数 :-) - Bergi

3

newjson是你的新对象,j是你的JSON。

这段代码非常快,因为它缓存了长度并且不使用push方法。

由于它是纯JavaScript,所以比所有的库都要快。

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);

根据Bergi的回答,您也可以使用while循环。

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;
}

你为什么认为不使用push会更好?顺便说一下,代码非常慢,因为它没有缓存相关的内容。 - Bergi
newjson[a]=tmpObj; 比 newjson.push(tmpObj) 更快。你想要缓存什么? - cocco
好的,如果您已经有了index,那就更好了,但是arr.push(x)arr[arr.length] = x之间没有相关区别。请参见https://dev59.com/rHRB5IYBdhLWcg3weHHx进行详细分析-应该使用更清晰易读的方式 :-) - Bergi
http://jsperf.com/reformat-json 这取决于浏览器,不管怎样缓存很棒 =) - cocco
我现在添加了一个while循环;) - cocco
是的,那可能会更快,但可读性会降低 :-) 尽管如此,我还是赞成。 - Bergi

2

使用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/


为什么你使用缓慢的 each 函数而不是 for 循环?Underscore 的方法看起来不同。 - Bergi
是的,您的下划线单行代码看起来更好。使用 _.partial 很不错,我以前从未用过这个。 - cr0

2
实际上,您可以使用 Array#map 来处理数组,并使用 Array#reduce 处理具有新属性的对象。

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; }

使用ES6,您可以使用Object.assign扩展语法...Object.assign会将属性添加到给定的对象并返回该对象。
扩展语法...接受一个数组,并将元素插入函数的参数中。

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; }


0

通过简单的JS,您的解决方案将如下所示:

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);


0

使用 JQuery:

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

例如,在GET请求之后,服务器会发送一个复杂的对象。
  $.get("/Files/-2", function (rxData, status) {

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

已登录控制台,可以通过 Chrome 的 Web 开发者工具(F12)进行探索,在我的情况下看起来像这样:

显示嵌套级别的图片


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接