Reputation: 4282
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
Upvotes: 1
Views: 9067
Reputation: 1083
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.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>
Upvotes: 3
Reputation: 1
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 comparing 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.net/sd7e9Lp7/3/
Upvotes: 1
Reputation: 147363
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 combine 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 compacted 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));
Upvotes: 1
Reputation: 31682
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;
Upvotes: 0