【问题标题】:Easiest way to interate over a complex JSON object via Javascript通过 Javascript 迭代复杂 JSON 对象的最简单方法
【发布时间】: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: 两个 为简单起见循环:-)

标签: javascript jquery json javascript-framework


【解决方案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 之间没有相关区别。有关详细分析,请参阅stackoverflow.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);
    

    【讨论】:

    【解决方案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.assignspread 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);

        【讨论】:

          猜你喜欢
          • 2020-05-14
          • 1970-01-01
          • 2011-05-23
          • 2020-10-15
          • 1970-01-01
          • 2014-01-01
          • 2018-08-19
          • 2019-04-30
          • 1970-01-01
          相关资源
          最近更新 更多