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

Posted

技术标签:

【中文标题】通过 Javascript 迭代复杂 JSON 对象的最简单方法【英文标题】:Easiest way to interate over a complex JSON object via Javascript 【发布时间】:2013-06-16 00:51:08 【问题描述】:

我正在使用的 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 最佳实践是什么?我可以使用 JQuery、Foundation JS 等 JS 框架来完成这项任务吗?

【问题讨论】:

您可以通过一个简单的循环来完成此操作。创建一个空对象,遍历COLUMNS,从DATA 获取数据并填充新对象。 @claustrofob: 两个 为简单起见循环:-) 【参考方案1】:

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

【讨论】:

【参考方案2】:

newjson 是你的新对象,j 是你的 json,

代码非常快,因为它会缓存长度并且不使用推送。

因为它是纯 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;

【讨论】:

为什么你认为不使用推送会更好?顺便说一句,代码很慢,因为它缓存相关的东西。 newjson[a]=tmpObj;比 newjson.push(tmpObj) 快。你想缓存什么? 好的,如果您已经拥有index 会更好,但arr.push(x)arr[arr.length] = x 之间没有相关区别。有关详细分析,请参阅***.com/q/614126 - 应该使用更清晰易读的内容:-) jsperf.com/reformat-json 是的,这取决于浏览器,无论如何都可以很好地使用缓存 =) 我现在添加了一个while--循环;)【参考方案3】:

您可以为此任务使用下划线数组函数

http://underscorejs.org/#arrays

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

来自文档: _.object(列表,[值]) 将数组转换为对象。传递 [key, value] 对的单个列表,或键列表和值列表..示例:

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

【讨论】:

嗯,你真的应该使用适当的 array function :-)【参考方案4】:

使用 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循环?下划线方法看起来不同。 是的,你的下划线单行看起来更好。 _.partial 不错,没用过。【参考方案5】:

实际上,您可以将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 和 spread syntax ...

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; 

【讨论】:

【参考方案6】:

使用 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 Developer (F12) 进行探索,在我的例子中是这样的:

image showing nested levels

【讨论】:

【参考方案7】:

通过简单的 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);

【讨论】:

以上是关于通过 Javascript 迭代复杂 JSON 对象的最简单方法的主要内容,如果未能解决你的问题,请参考以下文章

我制作了一个JavaScript对象,无法对其进行迭代,甚至无法访问其参数。我想念什么?

在 Javascript 中迭代 JSON 字符串的最快方法

javascript 思考:迭代复杂性

Javascript - 使用 HTML 片段通过电子邮件发送 JSON 输出

仅当特定密钥对值与可迭代匹配时,才在 JSON 对象中获取多个 JSON 密钥对值

我有一个对象的 .log 文件,如何将它们转换为 JSON 对象以便在 Javascript 中进行迭代?