I have an array of data like so:
[
{id: 1, date: "2022-10-01T12:00:00.00", type: 1},
{id: 2, date: "2022-10-02T12:00:00.00", type: 1},
{id: 3, date: "2022-10-03T12:00:00.00", type: 2},
{id: 4, date: "2022-10-04T12:00:00.00", type: 2},
]
I'd like to filter this so that I get an array of objects that only includes objects with the most recent date
for each type
. So something like this:
[
{id: 2, dttm: "2022-10-02T12:00:00.00", type: 1},
{id: 4, dttm: "2022-10-04T12:00:00.00", type: 2},
]
I suspect there's a clever way to do this with the .reduce()
function, but I haven't quite figured that out yet.
CodePudding user response:
It's easy to compare dates this way just using string comparing since they are sorted by year-month-date. As for the rest, yes reduce
is an option but basically it's just a loop over the array grouping by type
.
var arr = [
{id: 1, date: "2022-10-01T12:00:00.00", type: 1},
{id: 2, date: "2022-10-02T12:00:00.00", type: 1},
{id: 3, date: "2022-10-03T12:00:00.00", type: 2},
{id: 4, date: "2022-10-04T12:00:00.00", type: 2},
];
var grouped = arr.reduce(function(agg, item) {
agg[item.type] = agg[item.type] || {
id: item.id,
dttm: item.date,
type: item.type
};
if (item.date > agg[item.type].dttm) {
agg[item.type].id = item.id
agg[item.type].dttm = item.date
}
return agg;
}, {})
console.log (Object.values(grouped))
CodePudding user response:
We can achieve this using .reduce
by keeping a running tally of the most recent items.
Note:
Date
s can be compared in js as their valueOf
method is equivalent to someDate.getTime()
which gives a nice integer for comparison.
let items = [{
id: 1,
date: "2022-10-01T12:00:00.00",
type: 1
},
{
id: 2,
date: "2022-10-02T12:00:00.00",
type: 1
},
{
id: 3,
date: "2022-10-03T12:00:00.00",
type: 2
},
{
id: 4,
date: "2022-10-04T12:00:00.00",
type: 2
},
]
let recentItems = Object.values(items.reduce((recent, item) => {
debugger;
if (
// type has not items yet
!recent[item.type]
// the current item is more recent
||
new Date(recent[item.type].date) < new Date(item.date)
) {
recent[item.type] = item
}
return recent;
}, {}))
console.log(recentItems)
CodePudding user response:
This does what you specify. (See in-code comments for more info.)
// Calls filter function on the data array and prints output
const data = getData();
console.log(recentOfEachType(data));
// Defines filter function
function recentOfEachType(arr){
// Sets up output array
let recents = [];
// Loops through data to populate output
for(const item of arr){
// Gets position of existing item with this type
const typeIndex = recents.findIndex(recent => recent.type === item.type);
// If no item with this type has been added yet
if(typeIndex < 0){
recents.push(item);
}
// If a newer item is found (ignoring items with identical timestamps)
else if(item.date > recents[typeIndex].date){
recents[typeIndex] = item;
}
// (else do nothing)
}
return recents;
}
// Creates oringal data array
function getData(){
return [
{id: 1, date: "2022-10-01T12:00:00.00", type: 1},
{id: 2, date: "2022-10-02T12:00:00.00", type: 1},
{id: 3, date: "2022-10-03T12:00:00.00", type: 2},
{id: 4, date: "2022-10-04T12:00:00.00", type: 2}
];
}