最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

Javascript - Array of objects group by year, month and date - Stack Overflow

programmeradmin5浏览0评论

I'm trying to sort an array of object by date month and week

myArray : [
            {'name' : 'example1', 'date' : '2011-01-01'},
            {'name' : 'example1', 'date' : '2011-01-02'},
            {'name' : 'example1', 'date' : '2011-02-02'},
            {'name' : 'example1', 'date' : '2011-02-15'},
            {'name' : 'example1', 'date' : '2011-02-17'},
            {'name' : 'example1', 'date' : '2012-01-01'},
            {'name' : 'example1', 'date' : '2012-03-03'},
]

I would like to have such a result :

result : [{
                    '2011': { // Year 2011
                        '01': { // January
                            '01' : [ // First week of January
                                {'name' : 'example1', 'date' : '2011-01-01'},
                                {'name' : 'example1', 'date' : '2011-01-02'},
                            ]
                        },
                        '02' : { // February
                            '01' : [ // First week of February
                                {'name' : 'example1', 'date' : '2011-02-02'},
                            ],
                            '03' : [
                                {'name' : 'example1', 'date' : '2011-02-15'},
                                {'name' : 'example1', 'date' : '2011-02-17'},
                            ]
                        }
                    },
                    '2012' : { // Year 2012
                        '01' : { // January
                            '01': [ // First week of January
                                {'name': 'example1', 'date': '2012-01-01'}
                            ]
                        },
                        '03': { // March
                            '01' : [ // First week of March
                                {'name' : 'example1', 'date' : '2012-03-03'},
                            ]
                        }
                    }
                }]

I use lodash.groupBy with return getISOWeek(obj.date) or return getMonth(obj.date) or return getYear(obj.date).

I managed to sort the data by year and month, year and week but I can't figure out how to do it for the three at the same time.

Thanks for your help

I'm trying to sort an array of object by date month and week

myArray : [
            {'name' : 'example1', 'date' : '2011-01-01'},
            {'name' : 'example1', 'date' : '2011-01-02'},
            {'name' : 'example1', 'date' : '2011-02-02'},
            {'name' : 'example1', 'date' : '2011-02-15'},
            {'name' : 'example1', 'date' : '2011-02-17'},
            {'name' : 'example1', 'date' : '2012-01-01'},
            {'name' : 'example1', 'date' : '2012-03-03'},
]

I would like to have such a result :

result : [{
                    '2011': { // Year 2011
                        '01': { // January
                            '01' : [ // First week of January
                                {'name' : 'example1', 'date' : '2011-01-01'},
                                {'name' : 'example1', 'date' : '2011-01-02'},
                            ]
                        },
                        '02' : { // February
                            '01' : [ // First week of February
                                {'name' : 'example1', 'date' : '2011-02-02'},
                            ],
                            '03' : [
                                {'name' : 'example1', 'date' : '2011-02-15'},
                                {'name' : 'example1', 'date' : '2011-02-17'},
                            ]
                        }
                    },
                    '2012' : { // Year 2012
                        '01' : { // January
                            '01': [ // First week of January
                                {'name': 'example1', 'date': '2012-01-01'}
                            ]
                        },
                        '03': { // March
                            '01' : [ // First week of March
                                {'name' : 'example1', 'date' : '2012-03-03'},
                            ]
                        }
                    }
                }]

I use lodash.groupBy with return getISOWeek(obj.date) or return getMonth(obj.date) or return getYear(obj.date).

I managed to sort the data by year and month, year and week but I can't figure out how to do it for the three at the same time.

Thanks for your help

Share Improve this question asked Apr 29, 2017 at 22:56 Léo CocoLéo Coco 4,30211 gold badges60 silver badges101 bronze badges 1
  • According to ISO, 2011-01-01 is in week 52 of 2010, not week 1 of 2011. The first week of 2011 is 2 to 8 January. – RobG Commented Apr 30, 2017 at 1:04
Add a ment  | 

4 Answers 4

Reset to default 3

Using lodash is the way to go.

var myArray = [
  {'name' : 'example1', 'date' : '2011-01-01'},
  {'name' : 'example1', 'date' : '2011-01-02'},
  {'name' : 'example1', 'date' : '2011-02-02'},
  {'name' : 'example1', 'date' : '2011-02-15'},
  {'name' : 'example1', 'date' : '2011-02-17'},
  {'name' : 'example1', 'date' : '2012-01-01'},
  {'name' : 'example1', 'date' : '2012-03-03'},
];

var orderedByMonths = _.groupBy(myArray, function(element) {
                          return element.date.substring(0,7);
                      });
            
var orderedByYears =  _.groupBy(orderedByMonths, function(month) {
                          return month[0].date.substring(0,4);
                      });

console.log(orderedByYears);
<script src="https://cdnjs.cloudflare./ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>

You can use for..of loop, String.prototype.match() with RegExp /\d+/ to get YYYY, and MM portions of "date" property value; Array.prototype.filter() to match YYYY-MM of object at input array to current object at for..of loop by paring YYYY with "-" and MM concatenated.

const myArray = [
  {'name' : 'example1', 'date' : '2011-01-01'},
  {'name' : 'example1', 'date' : '2011-01-02'},
  {'name' : 'example1', 'date' : '2011-02-02'},
  {'name' : 'example1', 'date' : '2011-02-15'},
  {'name' : 'example1', 'date' : '2011-02-17'},
  {'name' : 'example1', 'date' : '2012-01-01'},
  {'name' : 'example1', 'date' : '2012-03-03'},
];

let res = {};

let fn = (year, month, o = res, array = myArray) => {
  o[year][month] = {
    [month]: array.filter(({date: d}) => `${year}-${month}` === d.slice(0, 7))
  };
}

for (let {date} of myArray) {
  let [year, month] = date.match(/\d+/g);
  if (!res[year]) res[year] = {};
  fn(year, month)
}

console.log(res);

jsfiddle https://jsfiddle/sd7e9Lp7/3/

It's really not clear from your question what you are after. ISO week numbers are based on years, not months, e.g. 2011-01-01 falls in the last week of 2010, not the first week of 2011. You really can't bine grouping by month and ISO week number, as about 10 weeks per year will start in one month and end in another.

If your concept of "week of the month" that a day falls in is simply Math.ceil(day number / 7), then you can group by that, noting that dates like 29 February, 2016 will be the only day of week 5 in February that year.

var data = [
  {'name' : 'example1', 'date' : '2011-01-01'},
  {'name' : 'example1', 'date' : '2011-01-02'},
  {'name' : 'example1', 'date' : '2011-02-02'},
  {'name' : 'example1', 'date' : '2011-02-15'},
  {'name' : 'example1', 'date' : '2011-02-17'},
  {'name' : 'example1', 'date' : '2012-01-01'},
  {'name' : 'example1', 'date' : '2012-03-03'},
];

function groupByMonthWeek(data) {
  var year, month, week
  return data.reduce(function (acc, obj) {
    var b = obj.date.split(/\D/);
    
    // Get custom week number, zero padded
    var weekNum = '0' + Math.ceil(b[2]/7);

    // Add year if not already present
    if (!acc[b[0]]) acc[b[0]] = {};
    year = acc[b[0]];
    
    // Add month if not already present
    if (!year[b[1]]) year[b[1]] = {};
    month = year[b[1]];
    
    // Add week if not already present
    if (!month[weekNum]) month[weekNum] = [];

    // Add object to  week
    month[weekNum].push(obj);

    return acc;    
  }, Object.create(null));
}

console.log(groupByMonthWeek(data));

Which, if you're into obfuscation, can be pacted to the following (but I wouldn't suggest actually using it):

var data = [
  {'name' : 'example1', 'date' : '2011-01-01'},
  {'name' : 'example1', 'date' : '2011-01-02'},
  {'name' : 'example1', 'date' : '2011-02-02'},
  {'name' : 'example1', 'date' : '2011-02-15'},
  {'name' : 'example1', 'date' : '2011-02-17'},
  {'name' : 'example1', 'date' : '2012-01-01'},
  {'name' : 'example1', 'date' : '2012-03-03'},
];

function groupByMonthWeek(data) {
  return data.reduce((acc, obj) => {
    var [y, m, d] = obj.date.split(/\D/);
    [y, m, '0'+Math.ceil(d/7)].reduce((a,v,i) => a[v] || (a[v] = i < 2 ? {} : []), acc).push(obj);
    return acc;
  }, Object.create(null));
}

console.log(groupByMonthWeek(data));

function group(arr) {
  return arr.reduce((r, o) => {
    var p = o.date.split("-");                             // get the parts: year, month and day
    var week = Math.floor(p.pop() / 7) + 1;                // calculate the week number (Math.floor(day / 7) + 1) and remove day from the parts array (p.pop())
    var month = p.reduce((o, p) => o[p] = o[p] || {}, r);  // get the month object (first, get the year object (if not create one), then get the month object (if not create one)
    if(month[week]) month[week].push(o);                   // if there is an array for this week in the month object, then push this object o into that array
    else month[week] = [o];                                // otherwise create a new array for this week that initially contains the object o
    return r;
  }, {});
}


let array = [{"name":"example1","date":"2011-01-01"},{"name":"example1","date":"2011-01-02"},{"name":"example1","date":"2011-02-02"},{"name":"example1","date":"2011-02-15"},{"name":"example1","date":"2011-02-17"},{"name":"example1","date":"2012-01-01"},{"name":"example1","date":"2012-03-03"}];

console.log(group(array));

If you want the week number to be in this format "01", "02", ... and not "1"; "2", ..., then change this line:

var week = Math.floor(p.pop() / 7) + 1;

to this:

var week = "0" + Math.floor(p.pop() / 7) + 1;
发布评论

评论列表(0)

  1. 暂无评论