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/app.component.ts
CodePudding user response:
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 firstDate = data.sort((a, b) => new Date(a) - new Date(b))[0];
console.log(firstDate);
console.log(String(firstDate)); // if you want a string
CodePudding user response:
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/[email protected]/moment.js"></script>
Explanation
- Use
.reduce()
to obtain anobject
with props as theyear
and values as the earliest date of that year - Use
Object.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 theorigData
array)- If the
year
of the currentitm
already exists, then check if the existing value in the aggregatorfin[moment(itm).format('YYYY')]
is lesser thanitm
(ie, whether the date is earlier than the one initm
) - If the existing date is earlier, do nothing (ie, return it as-is)
- Otherwise, repopulate the value with
itm