Javascript 将JSON数据分组为周/月,而无需额外的外部库?

Javascript 将JSON数据分组为周/月,而无需额外的外部库?,javascript,jquery,json,Javascript,Jquery,Json,我正在寻找一种解决方案,在没有外部库的情况下将数据分组为周/月。我在这里看到了D3.js nest()选项: 这里是使用npm的另一种方法: 也许我在拨号时代长大是疯了,但我仍然喜欢将我在一个页面上加载的内容减到实际需要的内容,而不是加载所有可能的内容,以防我想使用它,即使用户“可能”已经从CDN缓存了一份副本 我目前正在使用Chart.js显示数据,也可以使用Bootstrap和jQuery。我希望能够在日、周、月之间切换图表,只使用javascript或jQuery,这似乎应该是一件相当常见

我正在寻找一种解决方案,在没有外部库的情况下将数据分组为周/月。我在这里看到了D3.js nest()选项:

这里是使用npm的另一种方法:

也许我在拨号时代长大是疯了,但我仍然喜欢将我在一个页面上加载的内容减到实际需要的内容,而不是加载所有可能的内容,以防我想使用它,即使用户“可能”已经从CDN缓存了一份副本

我目前正在使用Chart.js显示数据,也可以使用Bootstrap和jQuery。我希望能够在日、周、月之间切换图表,只使用javascript或jQuery,这似乎应该是一件相当常见的事情,但如果不使用上面提到的更大的库,我看不到任何示例

var chart={
                dates: ['2015-09-01', '2015-09-02', '2015-09-03', '2015-09-04', '2015-09-05', '2015-09-06', '2015-09-07', '2015-09-08', '2015-09-09', '2015-09-10', '2015-09-11', '2015-09-12', '2015-09-13', '2015-09-14', '2015-09-15', '2015-09-16', '2015-09-17', '2015-09-18', '2015-09-19', '2015-09-20', '2015-09-21', '2015-09-22', '2015-09-23', '2015-09-24', '2015-09-25', '2015-09-26', '2015-09-27', '2015-09-28', '2015-09-29', '2015-09-30', '2015-10-01', '2015-10-02', '2015-10-03', '2015-10-04', '2015-10-05', '2015-10-06', '2015-10-07', '2015-10-08', '2015-10-09', '2015-10-10', '2015-10-11', '2015-10-12', '2015-10-13', '2015-10-14', '2015-10-15', '2015-10-16', '2015-10-17', '2015-10-18', '2015-10-19', '2015-10-20', '2015-10-21', '2015-10-22', '2015-10-23', '2015-10-24', '2015-10-25', '2015-10-26', '2015-10-27', '2015-10-28', '2015-10-29', '2015-10-30', '2015-10-31', '2015-11-01', '2015-11-02', '2015-11-03', '2015-11-04', '2015-11-05', '2015-11-06', '2015-11-07', '2015-11-08', '2015-11-09', '2015-11-10', '2015-11-11', '2015-11-12', '2015-11-13', '2015-11-14', '2015-11-15', '2015-11-16', '2015-11-17', '2015-11-18', '2015-11-19', '2015-11-20', '2015-11-21', '2015-11-22', '2015-11-23', '2015-11-24', '2015-11-25', '2015-11-26', '2015-11-27', '2015-11-28', '2015-11-29', '2015-11-30', '2015-12-01', '2015-12-02', '2015-12-03', '2015-12-04', '2015-12-05', '2015-12-06', '2015-12-07', '2015-12-08', '2015-12-09', '2015-12-10', '2015-12-11', '2015-12-12', '2015-12-13', '2015-12-14', '2015-12-15', '2015-12-16', '2015-12-17', '2015-12-18', '2015-12-19', '2015-12-20', '2015-12-21', '2015-12-22', '2015-12-23', '2015-12-24', '2015-12-25', '2015-12-26', '2015-12-27', '2015-12-28', '2015-12-29', '2015-12-30', '2015-12-31', '2016-01-01', '2016-01-02', '2016-01-03', '2016-01-04', '2016-01-05', '2016-01-06', '2016-01-07', '2016-01-08', '2016-01-09', '2016-01-10', '2016-01-11', '2016-01-12', '2016-01-13', '2016-01-14', '2016-01-15', '2016-01-16', '2016-01-17', '2016-01-18', '2016-01-19', '2016-01-20', '2016-01-21', '2016-01-22', '2016-01-23', '2016-01-24', '2016-01-25', '2016-01-26', '2016-01-27', '2016-01-28', '2016-01-29', '2016-01-30', '2016-01-31', '2016-02-01', '2016-02-02', '2016-02-03', '2016-02-04', '2016-02-05', '2016-02-06', '2016-02-07', '2016-02-08', '2016-02-09', '2016-02-10', '2016-02-11', '2016-02-12', '2016-02-13', '2016-02-14', '2016-02-15', '2016-02-16', '2016-02-17', '2016-02-18', '2016-02-19', '2016-02-20', '2016-02-21', '2016-02-22', '2016-02-23', '2016-02-24', '2016-02-25', '2016-02-26', '2016-02-27', '2016-02-28', '2016-02-29'],
                data: [77.02, 63.80, 21.64, 86.60, 65.40, 46.25, 27.38, 66.65, 67.25, 65.59, 64.80, 01.00, 32.75, 04.30, 51.92, 02.75, 40.20, 72.30, 62.90, 83.60, 66.66, 37.30, 93.90, 01.50, 55.77, 50.00, 73.20, 30.03, 07.95, 21.65, 07.93, 66.94, 11.72, 33.75, 22.80, 14.55, 68.78, 66.78, 52.35, 06.24, 64.78, 22.21, 19.08, 23.69, 54.40, 39.55, 28.76, 22.25, 09.85, 07.50, 22.47, 75.94, 93.34, 16.29, 28.98, 64.40, 78.68, 30.65, 96.65, 99.35, 77.50, 75.30, 89.85, 97.50, 53.90, 97.55, 28.98, 75.08, 25.66, 41.00, 73.72, 68.50, 95.40, 49.50, 32.50, 86.00, 05.43, 88.19, 50.39, 03.90, 82.90, 53.78, 94.20, 82.40, 12.63, 78.80, 07.50, 66.50, 41.75, 91.25, 34.50, 22.50, 85.50, 80.00, 33.75, 59.50, 52.50, 73.25, 76.50, 38.75, 11.00, 55.00, 37.25, 92.50, 74.75, 55.75, 37.25, 61.01, 90.95, 87.65, 99.08, 84.49, 47.00, 72.20, 45.95, 44.35, 10.90, 27.05, 63.10, 63.50, 66.48, 97.25, 39.85, 81.50, 57.90, 02.78, 72.95, 41.55, 39.44, 15.85, 06.60, 13.60, 87.10, 86.40, 90.75, 48.30, 29.75, 16.25, 20.51, 45.40, 51.10, 82.00, 24.24, 92.88, 81.75, 18.50, 89.15, 55.75, 53.50, 74.90, 41.35, 61.40, 07.80, 56.80, 33.75, 75.02, 78.50, 46.10, 39.25, 95.00, 22.85, 36.00, 43.53, 63.80, 32.85, 88.30, 89.69, 05.75, 16.15, 15.25, 20.55, 44.50, 46.28, 71.75, 19.45, 41.75, 25.75, 09.05, 58.77, 76.20, 30.45, 71.75]
            };

我假设日期格式为示例中的YYYY-MM-DD,为了方便起见,我将日期和数据保存在不同的数组中

var dates = chart.dates;
var data = chart.data;
记住以上假设,您可以轻松地按月份对数据进行分组

var groupByMonth = {};
dates.forEach(function (d, i) {

    var v = data[i];  
    var monthYear = d.slice(0, 7);    
    if (groupByMonth.hasOwnProperty(monthYear)) {
        groupByMonth[monthYear].push(v);
    } else {
        groupByMonth[monthYear] = [v];
    }
});

console.log(groupByMonth)
然而,要按周分组,您需要找到周数。这里有一个扩展方法可以实现这一点:

Date.prototype.getWeekNumber = function(){
    var d = new Date(+this);
    d.setHours(0,0,0);
    d.setDate(d.getDate()+4-(d.getDay()||7));
    return Math.ceil((((d-new Date(d.getFullYear(),0,1))/8.64e7)+1)/7);
};
使用上述扩展方法,您也可以轻松地按周数对数据进行分组。周数每年都会重复,因此,我使用周和年的组合来识别优衣库的任何一周

var groupByWeek = {};
dates.forEach(function (d, i) {

    var v = data[i];
    var weekYear = d.slice(0, 4) + '-' + new Date(d).getWeekNumber();
    if (groupByWeek.hasOwnProperty(weekYear)) {
        groupByWeek[weekYear].push(v);
    } else {
        groupByWeek[weekYear] = [v];
    }
});

console.log(groupByWeek)

我假设日期格式为示例中的YYYY-MM-DD,为了方便起见,我将日期和数据保存在不同的数组中

var dates = chart.dates;
var data = chart.data;
记住以上假设,您可以轻松地按月份对数据进行分组

var groupByMonth = {};
dates.forEach(function (d, i) {

    var v = data[i];  
    var monthYear = d.slice(0, 7);    
    if (groupByMonth.hasOwnProperty(monthYear)) {
        groupByMonth[monthYear].push(v);
    } else {
        groupByMonth[monthYear] = [v];
    }
});

console.log(groupByMonth)
然而,要按周分组,您需要找到周数。这里有一个扩展方法可以实现这一点:

Date.prototype.getWeekNumber = function(){
    var d = new Date(+this);
    d.setHours(0,0,0);
    d.setDate(d.getDate()+4-(d.getDay()||7));
    return Math.ceil((((d-new Date(d.getFullYear(),0,1))/8.64e7)+1)/7);
};
使用上述扩展方法,您也可以轻松地按周数对数据进行分组。周数每年都会重复,因此,我使用周和年的组合来识别优衣库的任何一周

var groupByWeek = {};
dates.forEach(function (d, i) {

    var v = data[i];
    var weekYear = d.slice(0, 4) + '-' + new Date(d).getWeekNumber();
    if (groupByWeek.hasOwnProperty(weekYear)) {
        groupByWeek[weekYear].push(v);
    } else {
        groupByWeek[weekYear] = [v];
    }
});

console.log(groupByWeek)

@Adnan Umer的解决方案可能更适合您的情况,因为您已经将日期作为字符串,但如果您使用的是日期而不是字符串,这里有一个更通用的方法:

function roundDate(date,type){
  var d = new Date(date) // so as to not override

  var types = ["day","week","month"]
  var idx = types.indexOf(type)

  if(idx > -1){ // remove all less than day
     d.setMilliseconds(0)
     d.setSeconds(0)
     d.setMinutes(0)
     d.setHours(0)
     if(idx > 0){ //remove day of the week
         d.setDate(d.getDate() - d.getDay()) // make it a sunday
         if(idx > 1){ //remove day of month
             d.setDate(1) 
         }
     }
  }

  return d;

}

function parseDate(str){ // in your case, we need to keep the date disregarding the locale offset
  return new Date(new Date(str).getTime() + new Date().getTimezoneOffset()*60*1000)
}


var lastDate = null
var grouping = "month"

var datesGrouped = []
var dataGrouped = []

function addToLast(arr,val){return arr[arr.length-1]+=val}

//I am assumming your dates are already sorted

chart.dates.map(function(date,index){
    data = chart.data[index] // get corresponding data point
    var group = roundDate(parseDate(date),grouping).getTime()
    if(group == lastDate){
        addToLast(dataGrouped, data)
    }else{
        datesGrouped.push(group)
        dataGrouped.push(data)
        lastDate = group
    }
})

console.log(datesGrouped, dataGrouped)

@Adnan Umer的解决方案可能更适合您的情况,因为您已经将日期作为字符串,但如果您使用的是日期而不是字符串,这里有一个更通用的方法:

function roundDate(date,type){
  var d = new Date(date) // so as to not override

  var types = ["day","week","month"]
  var idx = types.indexOf(type)

  if(idx > -1){ // remove all less than day
     d.setMilliseconds(0)
     d.setSeconds(0)
     d.setMinutes(0)
     d.setHours(0)
     if(idx > 0){ //remove day of the week
         d.setDate(d.getDate() - d.getDay()) // make it a sunday
         if(idx > 1){ //remove day of month
             d.setDate(1) 
         }
     }
  }

  return d;

}

function parseDate(str){ // in your case, we need to keep the date disregarding the locale offset
  return new Date(new Date(str).getTime() + new Date().getTimezoneOffset()*60*1000)
}


var lastDate = null
var grouping = "month"

var datesGrouped = []
var dataGrouped = []

function addToLast(arr,val){return arr[arr.length-1]+=val}

//I am assumming your dates are already sorted

chart.dates.map(function(date,index){
    data = chart.data[index] // get corresponding data point
    var group = roundDate(parseDate(date),grouping).getTime()
    if(group == lastDate){
        addToLast(dataGrouped, data)
    }else{
        datesGrouped.push(group)
        dataGrouped.push(data)
        lastDate = group
    }
})

console.log(datesGrouped, dataGrouped)

在您的情况下,组是否意味着添加数据值?另外,您想按日历周或从第一次约会开始的7天进行分组吗?谢谢您的评论,是的,我想对数据下的值进行合计,我可能会按周日到周日的日历进行分组,而不仅仅是按周五到周五的随机分组。任何您可以找到的库都可以自己编写,但是,在javascript中,日期操作是非常棘手的,如果你能找到一个做你想要的事情的库,你可能就应该使用它。在你的例子中,这个组是否意味着要添加数据值?另外,您想按日历周或从第一次约会开始的7天进行分组吗?谢谢您的评论,是的,我想对数据下的值进行合计,我可能会按周日到周日的日历进行分组,而不仅仅是按周五到周五的随机分组。任何您可以找到的库都可以自己编写,但是,在javascript中,日期操纵是非常棘手的,如果你能找到一个能做你想要的事情的库,你可能就应该使用它。非常棒的解决方案,谢谢!我一直在玩这一个,也有一些承诺,但你的是这么短,干净得多。真棒的解决方案,谢谢!我一直在玩这一个,也有一些承诺,但你的是这么短,干净得多。