【问题标题】:How can I group an array of objects by month?如何按月对一组对象进行分组?
【发布时间】:2013-07-25 14:08:30
【问题描述】:

我正在使用 JavaScript。我有一个包含这种格式数据的数组:

[
        {"USER_NAME":"User1","LAST_SUCCESSFUL_CONNECT":"1373978337642"},
        {"USER_NAME":"User2","LAST_SUCCESSFUL_CONNECT":"1374515704026"},
        {"USER_NAME":"User3","LAST_SUCCESSFUL_CONNECT":"1374749782479"}
]

(上面的数字以毫秒为单位表示 UTC 日期/时间。

我想按月对数据进行分组(计数)。像这样的:

[
    {"Month":"January, 2014","User_Count": 2},
    {"Month":"February, 2014","User_Count": 1},
]

如果可以简化问题,我可以使用jQuery

【问题讨论】:

  • 这个对象是从服务器返回的吗?如果是这样,我建议以正确的格式将数据返回给客户端,而不是在 java 脚本中添加解析逻辑。在服务器上运行这种类型的逻辑通常更容易且更易于单元测试。
  • 是的,我正在从oData 的服务器获取数据。这意味着我什至可能不必更改服务器代码,而是使用 oData 的 $count 选项(我不确定这会给我想要的东西)。但是,我已经在客户端中获得了先前查询的原始数据,我想保存往返行程。
  • 如果我在下面的回答确实令人满意,请将此问题标记为已回答。否则,请详细说明。

标签: javascript count group-by date-range


【解决方案1】:

这看起来像是 map reduce 问题。高级解决方案如下:

  1. 重新组织列表的成员。
  2. 数一数。

以下是实现此目的的分步操作方法:

地图

  1. 遍历字典列表
  2. 将日期时间字符串转换为 javascript 日期时间对象。
  3. 使用月份-年份作为键,字典列表作为值。

这些现在按月-年分组。

示例:

var l = [...];
var o = {};
var f = function(x){
    var dt_object = Date(x["LAST_SUCCESSFUL_CONNECT"]); // convert to datetime object
    var key = dt_object.year + '-' + dt_object.month;

    if (o[key] === undefined) {
        var o[key] = [];
    };

    o[key].push(x)
}

_.map(l, f(x)) //apply f to each member of l

减少

  1. 遍历包含列表字典的新对象。
  2. 计算每个字典列表的长度。
  3. 使用count 作为键,使用列表长度作为值。

示例:

var g = function(member_count){
    //extra logic may go here
    return member_count
}

for member in o {
    count = _.reduce(l, g(member))
    member['count'] = count
}

生成的 API

o['month-year'] //for list of dictionaries in that month
o['month-year']['count'] //for the count of list of dictionaries in that month.

参考资料:

对于 javascript 中的 mapreduce 函数,请参阅 underscore.js:
http://underscorejs.org/#map
http://underscorejs.org/#reduce

Javascript 日期对象:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date

有关 Date 和 DateTime 对象的更多信息:
https://en.wikipedia.org/wiki/ISO_8601

有关mapreduce的更多信息:
https://en.wikipedia.org/wiki/MapReduce

【讨论】:

  • 感谢 @pygeek 的详尽回答。我不能使用 jQuery 以外的开源或 3rd 方源,所以 underscorejs 不适合我。我将使用 jQuery 的 map 和 JavaScript 的 Array reduce。
【解决方案2】:

使用 Map-reduce。这是一个使用 underscore.js 的示例。虽然有点冗长,但很简单。

var data = [{
    "USER_NAME": "User1",
        "LAST_SUCCESSFUL_CONNECT": "1373978337642"
}, {
    "USER_NAME": "User2",
        "LAST_SUCCESSFUL_CONNECT": "1374515704026"
}, {
    "USER_NAME": "User3",
        "LAST_SUCCESSFUL_CONNECT": "1374749782479"
}, {
    "USER_NAME": "User4",
        "LAST_SUCCESSFUL_CONNECT": "1274749702479"
}];

var monthNames = ["January", "February", "March", "April", "May", "June",
    "July", "August", "September", "October", "November", "December"];

var map_result = _.map(data, function (item) {
    var d = new Date(new Number(item.LAST_SUCCESSFUL_CONNECT));
    var month = monthNames[d.getMonth()] + ", " + d.getFullYear();
    return {
        "Month": month,
        "User_Count": 1
    };
});

var result_temp = _.reduce(map_result, function (memo, item) {
    if (memo[item.Month] === undefined) {
        memo[item.Month] = item.User_Count;
    }else{
        memo[item.Month] += item.User_Count;
    }
    return memo;
},{});

//then wrap the result to the format you expected.
var result = _.map(result_temp, function(value, key){
    return {
        "Month": key,
        "User_Count": value
    };
});

console.log(result); 

【讨论】:

    【解决方案3】:

    也许这会有用

    LINQ for JavaScript
    http://linqjs.codeplex.com/

    【讨论】:

      【解决方案4】:

      优化方案

      var map_month= {}  
      const monthNames = ["Jan", "Feb", "Mar", "Apr", "May", "Jun",
        "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
      ];
      
      for (const x of o) {
                
         GroupBy(x["LAST_SUCCESSFUL_CONNECT"])
      }
      
      const GroupBy = (elem) => {
             
             dateObj = new Date(elem) 
      
             monthObj = monthNames[dateObj.getMonth()] + " " + dateObj.getFullYear()
             if(map_month[monthObj]===undefined)
                map_month[monthObj+""]  = 1;
             else map_month[monthObj] += 1;
      
        } 
      

      【讨论】:

      • 它是如何优化的解决方案,解释它,至少你的代码应该是可运行的。它有多个错误。
      猜你喜欢
      • 2019-02-20
      • 2022-01-08
      相关资源
      最近更新 更多