Reputation: 112
I have an array-snapshot out of Firebase, which contains the entries of my application. Among other information there is a a timestamp called "referenceDate":
entry [0] { referenceDate: 2017-08-03,...
entry [1] { referenceDate: 2017-08-02,...
entry [2] { referenceDate: 2017-08-01,...
entry [3] { referenceDate: 2017-07-03,...
entry [4] { referenceDate: 2017-07-02,...
I want to output the entries grouped under a headline by month and year like this
08.2017
03.08.2017
02.08.2017
01.08.2018
07.2017
03.07.2017
02.07.2017
My idea is to loop over the array-snapshot and create another nested one which looks like this:
{"monthYear": "08.2017":[
{"referenzDatum": 2017-08-03},... },
{"referenzDatum": 2017-08-02},... },
{"referenzDatum": 2017-08-01},... },]},
{"monthYear": "07.2017":[
{"referenzDatum": 2017-07-03},... },
{"referenzDatum": 2017-07-02},... }, ...]}
Then loop over it with two nested ngFor to generate the html output.
Is there a simple way to achieve this? I tried to just push the old entry into the new array according to the corresponding monthyear whenever this changes, but that didnt work out, because references were copied. then I tried the following code, but it doesn't really work for more than 2 different months and the code just looks awful.
var oldDate: string;
var newDate: string;
sortedLogLine.entries = [];
this.sortedLog = [];
for (var i = 0; i < entries.length; i++) {
newDate = entries[i].referenceDate.substring(0, 7).split('-').reverse().join('.');
if (oldDate == newDate) {
sortedLogLine.entries.push(entries[i]);
}
if (!oldDate) {
sortedLogLine.entries.push(entries[i]);
sortedLogLine.monthYear = newDate;
oldDate = newDate;
}
if (oldDate != newDate) {
pushSortedLogLine.entries = sortedLogLine.entries.slice(0);
pushSortedLogLine.monthYear = oldDate;
this.sortedLog.push(pushSortedLogLine);
sortedLogLine.entries = [];
sortedLogLine.entries.push(entries[i]);
sortedLogLine.monthYear = newDate;
oldDate = newDate;
}
}
this.sortedLog.push(sortedLogLine);
Any suggestions as to how to do this more efficiently?
Upvotes: 2
Views: 75
Reputation: 149
Try this:
const entries = [{ referenceDate: '2017-08-03'}, { referenceDate: '2017-08-02'}, { referenceDate: '2017-08-01'}, { referenceDate: '2017-07-03'}, { referenceDate: '2017-07-02'}];
const resultObj = {};
for (var i = 0; i < entries.length; i++) {
const month = entries[i].referenceDate.substring(0, 7).split('-').reverse().join('.');
if (!resultObj[month]) {
resultObj[month] = [];
}
resultObj[month].push(entries[i]);
}
const out = document.getElementsByClassName('json')[0];
out.innerHTML = JSON.stringify(resultObj, undefined, 2);
<pre class="json"></pre>
Upvotes: 0
Reputation: 11235
var arrayOfDates = [
{'referenceDate':'2017-08-03'},
{'referenceDate':'2017-08-02'},
{'referenceDate':'2017-08-01'},
{'referenceDate':'2017-07-03'},
{'referenceDate':'2017-07-02'}
];
var result = [];
arrayOfDates.forEach(function(entry) {
var date = new Date(entry.referenceDate);
var day = date.getDate();
var monthIndex = date.getMonth() +1;
var year = date.getFullYear();
var keyDateFormat = monthIndex+'.'+year;
if(!(keyDateFormat in result)) {
result[keyDateFormat] = [];
}
result[keyDateFormat].push(entry);
});
Upvotes: 1
Reputation: 138567
Probably use a hash table:
var timetable = {};
data.forEach(function(el){
var d = new Date(el.referenceDate),
y = d.getFullYear(),
m = d.getMonths() +1;
if(!timetable[y]) timetable[y] = [];
if(!timetable[y][m]) timetable[y][m] = [];
timetable[y][m].push(el);
});
Then you can get all available years, sort and display them:
Object.values(timetable).sort((a,b)=>a-b).forEach(function(year){
console.log(year);
for(var [month,entries] of timetable[year].entries()){
console.log(month,entries.join("\n"));
}
});
Upvotes: 0
Reputation: 95395
The usual way to do something like this would be groupBy
. Javascript doesn't have a native groupBy method on its Arrays, but several helper libraries like underscore.js do. Alternatively, you can roll your own with reduce
:
let getMonthYear = (obj) => obj.referenceDate.split('-').reverse().slice(1).join('.');
let groupBy = (ary, fn) => ary.reduce(function(groups, item) {
let key = fn(item)
if (!groups[key]) groups[key]=[]
groups[key].push(item)
return groups;
}, {});
let entries = [ { referenceDate: '2017-08-03' },
{ referenceDate: '2017-08-02' },
{ referenceDate: '2017-08-01' },
{ referenceDate: '2017-07-03' },
{ referenceDate: '2017-07-02' } ]
let groups = groupBy(entries, getMonthYear);
console.log(groups)
which produces this output:
{ '08.2017':
[ { referenceDate: '2017-08-03' },
{ referenceDate: '2017-08-02' },
{ referenceDate: '2017-08-01' } ],
'07.2017':
[ { referenceDate: '2017-07-03' },
{ referenceDate: '2017-07-02' } ] }
See also this similar question.
Upvotes: 1
Reputation: 3671
Have a look at Lodash, specifically groupBy
I believe Lodash is a better choice over Underscore.js, more details in this blog post
Upvotes: 0