【问题标题】:JavaScript SUM and GROUP BY of JSON dataJSON 数据的 JavaScript SUM 和 GROUP BY
【发布时间】:2012-06-26 01:27:43
【问题描述】:

这是我第一次尝试使用一些 JSON 数据对象执行 JavaScript,需要一些关于实现目标的正确方法的建议。

一些服务器端代码实际上会生成一个 JSON 格式的字符串,我必须使用它并将其分配给一个字符串:

var dataString='$DATASTRING$';

但是在服务器替换其数据后我必须处理的最终结果(当然没有 \r\n):

var dataString='[ 
 { "category" : "Search Engines", "hits" : 5, "bytes" : 50189 },
 { "category" : "Content Server", "hits" : 1, "bytes" : 17308 },
 { "category" : "Content Server", "hits" : 1, "bytes" : 47412 },
 { "category" : "Search Engines", "hits" : 1, "bytes" : 7601 },
 { "category" : "Business", "hits" : 1, "bytes" : 2847 },
 { "category" : "Content Server", "hits" : 1, "bytes" : 24210 },
 { "category" : "Internet Services", "hits" : 1, "bytes" : 3690 },
 { "category" : "Search Engines", "hits" : 6, "bytes" : 613036 },
 { "category" : "Search Engines", "hits" : 1, "bytes" : 2858 } 
]';

然后我可以将其更改为要使用的对象。

var dataObject=eval("("+dataString+")");

这允许我访问数据的各个行,但我需要对这些值进行求和、分组和排序。

我需要类似这样的 SQL 语句:

SELECT category, sum(hits), sum(bytes) 
FROM dataObject
GROUP BY category
ORDER BY sum(bytes) DESC

我想要的输出是这样的对象,我可以进一步处理:

var aggregatedObject='[ 
 { "category" : "Search Engines", "hits" : 13, "bytes" : 673684 },
 { "category" : "Content Server", "hits" : 3, "bytes" : 88930 },
 { "category" : "Internet Services", "hits" : 1, "bytes" : 3690 },
 { "category" : "Business", "hits" : 1, "bytes" : 2847 } 
]';

...但我不知道从哪里开始。

我可以遍历所有类别值并首先找到唯一的类别,然后再次循环并对命中和字节求和,然后再次进行排序,但似乎必须有一种更简单的方法。

prototype.js (1.7) 已经包含在客户端页面中,但如果需要,我可以添加 Underscore、jQuery 或其他一些小型库。

我只是不知道用最少的代码来处理查询是最好的、最简单的、最小的。

有什么建议吗?

【问题讨论】:

  • LINQ to JS 可能没有您需要的一切,但它可能对您有所帮助
  • 不错。开始寻找的好地方,但仍然需要 jQuery 来实现聚合函数。比我想要的多一点。可以为我想到的另一个项目派上用场。谢谢

标签: javascript json group-by sum


【解决方案1】:

你可以使用原生函数.reduce()聚合数据,然后.sort()按照bytes排序。

var result = dataObject.reduce(function(res, obj) {
    if (!(obj.category in res))
        res.__array.push(res[obj.category] = obj);
    else {
        res[obj.category].hits += obj.hits;
        res[obj.category].bytes += obj.bytes;
    }
    return res;
}, {__array:[]}).__array
                .sort(function(a,b) { return b.bytes - a.bytes; });

如果您支持较旧的实现,则需要使用shim for .reduce()

【讨论】:

  • 美丽。完全符合我的要求,只需要一个小垫片来减少。 (甚至可以在 IE6 中使用 :) 我认为这是我缺少的关键,因为我看到 .reduce 被提及但永远无法让它工作。似乎具有最低的开销并且可以满足我的需要。太棒了。
  • 嗯。现在我想知道是否有一个简单的方法来绘制这个?我只是要做一个文本表,但可能是字节或命中的图表。有什么好的绘图程序吗?
  • @LordChariot:Google 可能会向您展示一些不错的绘图库。先试一试,如果遇到问题,再问一个问题。 :)
  • 哇...我也在寻找这个...谢谢.. 1 Up for the answer... :)
  • 看来你的回调函数不是纯函数。它改变了原始数组。这样我们就不能重用初始数据来处理另一个步骤。顺便说一句,谢谢你的回答。
【解决方案2】:

如果你走LINQ.js路线,你可以这样做:

var aggregatedObject = Enumerable.From(dataArray)
        .GroupBy("$.category", null,
                 function (key, g) {
                     return {
                       category: key,
                       hits: g.Sum("$.hits"),
                       bytes: g.Sum("$.bytes")
                     }
        })
        .ToArray();

Stack Snippets 的工作演示:

var dataArray = [ 
  { category: "Search Engines", hits: 5, bytes: 50189 },
  { category: "Content Server", hits: 1, bytes: 17308 },
  { category: "Content Server", hits: 1, bytes: 47412 },
  { category: "Search Engines", hits: 1, bytes: 7601  },
  { category: "Business",       hits: 1, bytes: 2847  },
  { category: "Content Server", hits: 1, bytes: 24210 },
  { category: "Internet ",      hits: 1, bytes: 3690  },
  { category: "Search Engines", hits: 6, bytes: 613036 },
  { category: "Search Engines", hits: 1, bytes: 2858  } 
];

var aggregatedObject = Enumerable.From(dataArray)
        .GroupBy("$.category", null,
                 function (key, g) {
                     return {
                       category: key,
                       hits: g.Sum("$.hits"),
                       bytes: g.Sum("$.bytes")
                     }
        })
        .ToArray();

console.log(aggregatedObject);
<script src="//cdnjs.cloudflare.com/ajax/libs/linq.js/2.2.0.2/linq.min.js"></script>

另外,你可以在linqjs group by with a sum找到更多信息

【讨论】:

    【解决方案3】:

    鉴于上面的 dataString,下面的代码似乎可以工作。它穿过每个对象;如果该类别存在于groupedObjects 数组中,则其命中数和字节数将添加到现有对象中。否则,它被认为是新的并添加到 groupedObjects 数组中。

    此解决方案使用 underscore.js 和 jQuery

    这是一个 jsfiddle 演示:http://jsfiddle.net/R3p4c/2/

    var objects = $.parseJSON(dataString);
    var categories = new Array();
    var groupedObjects = new Array();
    var i = 0;
    
    _.each(objects,function(obj){
        var existingObj;
        if($.inArray(obj.category,categories) >= 0) {
            existingObj = _.find(objects,function(o){return o.category === obj.category; });
            existingObj.hits += obj.hits;
            existingObj.bytes += obj.bytes;
        } else {
            groupedObjects[i] = obj;
            categories[i] = obj.category;
            i++;
      }
    });
    
    groupedObjects = _.sortBy(groupedObjects,function(obj){ return obj.bytes; }).reverse();
    

    【讨论】:

    • 是的。完全按照我的意愿去做。我将收到的实际完整数据集(1000 多个数组元素)放入 jsfiddle 中,结果得到了正确的值。缺点是它需要下划线和 jQuery。我希望减少我必须包含的行李数量。 (不能热链接到外部,因为它可能在一个封闭的网络上)但总的来说,我喜欢我可能很快会做的其他一些事情的灵活性。
    【解决方案4】:
    var obj = [{Poz:'F1',Cap:10},{Poz:'F1',Cap:5},{Poz:'F1',Cap:5},{Poz:'F2',Cap:20},{Poz:'F1',Cap:5},{Poz:'F1',Cap:15},{Poz:'F2',Cap:5},{Poz:'F3',Cap:5},{Poz:'F4',Cap:5},{Poz:'F1',Cap:5}];
    Array.prototype.sumUnic = function(name, sumName){
        var returnArr = [];
        var obj = this;
        for(var x = 0; x<obj.length; x++){
            if((function(source){
                if(returnArr.length == 0){
                    return true;
                }else{
                    for(var y = 0; y<returnArr.length; y++){
                        var isThere = [];
                        if(returnArr[y][name] == source[name]){
                            returnArr[y][sumName] = parseInt(returnArr[y][sumName]) + parseInt(source[sumName]);
                            return false;
                        }else{
                            isThere.push(source);
                        }
                    }
                    if(isThere.length>0)returnArr.push(source);
                    return false;
                }
            })(obj[x])){
                returnArr.push(obj[x]);
            }
        }
        return returnArr;
    }
    obj.sumUnic('Poz','Cap');
    // return "[{"Poz":"F1","Cap":45},{"Poz":"F2","Cap":25},{"Poz":"F3","Cap":5},{"Poz":"F4","Cap":5}]"
    

    【讨论】:

      【解决方案5】:

      嗨,这是我写的一个解决方案访问:aggregate_groupby_js on npmaggregate_groupby_js on github

      用于在对象数组上使用聚合函数的 javascript 库。整个 javascript 对象的基本函数,如 SUM、MIN、MAX、AVG、DISTINCT_COUNT

      例子:

      var arr = [{`"shape"`:`"square"`,`"color"`:`"red"`,`"used"`:1,`"instances"`:1},
          {`"shape"`:`"square"`,`"color"`:`"red"`,`"used"`:2,`"instances"`:1},
          {`"shape"`:`"circle"`,`"color"`:`"blue"`,`"used"`:0,`"instances"`:0},
          {`"shape"`:`"square"`,`"color"`:`"blue"`,`"used"`:4,`"instances"`:4},
          {`"shape"`:`"circle"`,`"color"`:`"red"`,"`used"`:1,`"instances"`:1},
          {`"shape"`:`"circle"`,`"color"`:`"red"`,`"used"`:1,`"instances"`:0},
          {`"shape"`:`"square"`,`"color"`:`"blue"`,`"used"`:4,`"instances"`:5}, 
          {`"shape"`:`"square"`,`"color"`:`"red"`,`"used"`:2,`"instances"`:1}];
      
      // Specify columns
          var columns =[`"used"`, `"instances"`];
      
      // Initialize object
          var gb = new GroupBy(arr,columns);
      // or
          var gb = new GroupBy(arr,[`"used"`, `"instances"`]);
      
      // Call the aggregate functions    
          gb.sum();
          gb.min();
          gb.max();
          gb.avg();
          gb.distinctCount();
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-01-19
        • 1970-01-01
        • 1970-01-01
        • 2021-01-30
        • 2021-05-09
        • 2016-06-21
        • 2012-09-18
        • 1970-01-01
        相关资源
        最近更新 更多