Right now I have a for-loop going over the dates. I first sort the order and then pluck the first date of each year, but I feel like this could be used with .reduce() instead and converting the results with Object.values(result) would return me the array or 3 dates.
Reducing with one tenerary would get me the lowest overall date. But I am stuck where I need to return the lowest date from each year within the section.
.reduce((a,b) =>
a = moment(a) < moment(a) ? a : b
return a
)
If there are better ways to achive the end result I am all ears.
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent {
firstDatesOfYear = [];
data = [
'2022-02-14T00:00:00',
'2021-06-14T00:00:00',
'2021-06-21T00:00:00',
'2021-11-01T00:00:00',
'2022-01-10T00:00:00',
'2022-01-03T00:00:00',
'2020-07-20T00:00:00',
'2020-08-31T00:00:00',
'2020-09-07T00:00:00',
'2021-02-22T00:00:00',
'2021-06-07T00:00:00',
'2022-01-17T00:00:00',
'2022-01-24T00:00:00',
'2022-01-31T00:00:00',
];
// find first date of each year from non sorted list of ISO dates
// result should be ["2020-07-20T00:00:00", "2021-02-22T00:00:00", "2022-01-03T00:00:00"]
constructor() {
let temp = this.data
.map((day) => moment(day))
.sort((a, b) => a.unix() - b.unix());
// stuck here, instead of doing the whole following below - should use .reduce()?
console.log(temp);
for (let i = 0; i < temp.length; i++) {
if (i == 0) {
this.firstDatesOfYear.push(temp[i]);
} else if (moment(temp[i]).year() != moment(temp[i + 1]).year()) {
this.firstDatesOfYear.push(temp[i + 1]);
}
}
}
}
Problem: https://stackblitz.com/edit/angular-moment-example-z7m92c?file=app%2Fapp.component.ts
Edit. I ended up using something like this.
.reduce((datesMap, curr) => {
const date = new Date(curr),
year = date.getFullYear();
if (datesMap.has(year)) {
if (date.getTime() < datesMap.get(year).getTime())
datesMap.set(year, date);
} else {
datesMap.set(year, date);
}
return datesMap;
}, new Map());
I don't pretend to know everything that's going on, but an easy way to find the first date is with .sort().
const data = [
"2022-02-14T00:00:00",
"2021-06-14T00:00:00",
"2021-06-21T00:00:00",
"2021-11-01T00:00:00",
"2022-01-10T00:00:00",
"2022-01-03T00:00:00",
"2020-07-20T00:00:00",
"2020-08-31T00:00:00",
"2020-09-07T00:00:00",
"2021-02-22T00:00:00",
"2021-06-07T00:00:00",
"2022-01-17T00:00:00",
"2022-01-24T00:00:00",
"2022-01-31T00:00:00",
];
const firstDatePerYear = data
.sort((a, b) => new Date(a) - new Date(b))
.reduce((acc, curr) => {
const year = new Date(curr).getFullYear();
if (!acc[year]) acc[year] = curr;
return acc;
}, {});
console.log(firstDatePerYear);
/*
{
'2020': '2020-07-20T00:00:00',
'2021': '2021-02-22T00:00:00',
'2022': '2022-01-03T00:00:00'
}
*/
The idea to use .reduce() is one possible way to achieve the objective. Combine it with Object.values() and below is one possible implementation:
const origData = [
'2022-02-14T00:00:00',
'2021-06-14T00:00:00',
'2021-06-21T00:00:00',
'2021-11-01T00:00:00',
'2022-01-10T00:00:00',
'2022-01-03T00:00:00',
'2020-07-20T00:00:00',
'2020-08-31T00:00:00',
'2020-09-07T00:00:00',
'2021-02-22T00:00:00',
'2021-06-07T00:00:00',
'2022-01-17T00:00:00',
'2022-01-24T00:00:00',
'2022-01-31T00:00:00',
];
const getFirstDates = (arr = origData) => (
Object.values(
arr.reduce(
(fin, itm) => ({
...fin,
[moment(itm).format('YYYY')]: (
fin[moment(itm).format('YYYY')] &&
fin[moment(itm).format('YYYY')] < itm
? fin[moment(itm).format('YYYY')]
: itm
)
}),
{}
)
)
);
console.log(getFirstDates());
<script src="https://unpkg.com/moment@2.29.1/moment.js"></script>
Explanation
.reduce() to obtain an object with props as the year and values as the earliest date of that yearObject.values() to extract just the values (which will be earliest date on each given year)How reduce works
fin is the aggregator & is initially set to {} (empty object)itm is the iterator (ie, each date in the origData array)year of the current itm already exists, then check if the existing value in the aggregator fin[moment(itm).format('YYYY')] is lesser than itm (ie, whether the date is earlier than the one in itm)itm