Reputation: 53
I have an array of objects for a podcast app that looks like this:
[{ id: "uuid-1"
timeInSeconds: 1000
dateListened: "2021-01-01T15:57:17.000Z" }, // <---same day
{ id: "uuid-2"
timeInSeconds: 4900
dateListened: "2021-01-01T16:57:17.000Z" }, // <---same day
{ id: "uuid-3"
timeInSeconds: 3200
dateListened: "2021-09-01T16:57:17.000Z" },
{ id: "uuid-4"
timeInSeconds: 6000
dateListened: "2021-10-01T16:57:17.000Z" } ]
I want to create a function that combines activity times if the dateListened
is on the same day. I want it to look something like this:
[{ id: "uuid-new"
timeInSeconds: 5900 // <---- combined seconds listened on Jan 1
dateListened: "2021-01-01T15:57:17.000Z" },
{ id: "uuid-3"
timeInSeconds: 3200
dateListened: "2021-09-01T16:57:17.000Z" },
{ id: "uuid-4"
timeInSeconds: 6000
dateListened: "2021-10-01T16:57:17.000Z" } ]
My closest attempts have been to use a .map() with a nested .some() but I'm still far off enough that it's not even worth posting my tries. Does anyone have any hints or ideas of what direction to try next? Thank you!
Upvotes: 0
Views: 43
Reputation: 48630
You could reduce the items and map them to a date key, retrieve the values, and then map them to single objects.
You can key on the following:
let date = new Date(info.dateListened).toLocaleDateString('en-US')
const data = [
{ id: "uuid-1",
timeInSeconds: 1000,
dateListened: "2021-01-01T15:57:17.000Z" }, // <---same day
{ id: "uuid-2",
timeInSeconds: 4900,
dateListened: "2021-01-01T16:57:17.000Z" }, // <---same day
{ id: "uuid-3",
timeInSeconds: 3200,
dateListened: "2021-09-01T16:57:17.000Z" },
{ id: "uuid-4",
timeInSeconds: 6000,
dateListened: "2021-10-01T16:57:17.000Z" }
];
const result = Object
.values(data.reduce((acc, info) =>
(date =>
({ ...acc, [date]: [...(acc[date] || []), info ] }))
(new Date(info.dateListened).toLocaleDateString('en-US')), {}))
.map(value => value.length === 1 ? value : {
id: 'uuid-new',
timeInSeconds: value.reduce((sum, { timeInSeconds }) => sum + timeInSeconds, 0),
dateListened: value[0].dateListened
});
console.log(result);
.as-console-wrapper { top: 0; max-height: 100% !important; }
Upvotes: 1
Reputation: 25408
You can achieve the result using reduce and only add the timeInSeconds
if its year
, month
, and date
is exactly the same/equal.
const arr = [
{
id: "uuid-1",
timeInSeconds: 1000,
dateListened: "2021-01-01T15:57:17.000Z",
},
{
id: "uuid-2",
timeInSeconds: 4900,
dateListened: "2021-01-01T16:57:17.000Z",
},
{
id: "uuid-3",
timeInSeconds: 3200,
dateListened: "2021-09-01T16:57:17.000Z",
},
{
id: "uuid-4",
timeInSeconds: 6000,
dateListened: "2021-10-01T16:57:17.000Z",
},
];
const result = arr.reduce((acc, curr) => {
const { id, timeInSeconds, dateListened } = curr;
const searchSameDateElement = acc.find((o) => {
const first = new Date(o.dateListened);
const second = new Date(dateListened);
const isYearSame = first.getFullYear() === second.getFullYear();
const isMonthSame = first.getMonth() === second.getMonth();
const isDateSame = first.getDate() === second.getDate();
return isYearSame && isMonthSame && isDateSame;
});
if (!searchSameDateElement) {
acc.push(curr);
} else {
searchSameDateElement.timeInSeconds += timeInSeconds;
}
return acc;
}, []);
console.log(result);
Upvotes: 0