Reputation: 141
Underneath is an array of objects containing two properties emp_name and date and I want to update records by adding flag in which date should be greatest among other date corresponding to emp_name.
let arr_of_obj = [{emp_name:'Mark',date:new Date('2018/05/01')},
{emp_name:'Mark',date:new Date('2018/05/02')},
{emp_name:'John',date:new Date('2018/04/05')},
{emp_name:'John',date:new Date('2018/03/22')},
{emp_name:'Mark',date:new Date('2018/05/06')}];
Suppose above arr_of_obj should updated two entries i.e.
[{emp_name:'Mark',date:new Date('2018/05/21')},
{emp_name:'Mark',date:new Date('2018/05/22')},
{emp_name:'John',date:new Date('2018/04/15'),max:true},
{emp_name:'John',date:new Date('2018/03/22')},
{emp_name:'Mark',date:new Date('2018/05/26'),max:true}]
Upvotes: 0
Views: 368
Reputation: 1248
Not bringing much more than @Engineer but I tend to avoid declaring const and then assigning properties to it, even if it's not a big deal. So I like using reduce here :
const max_dates = arr_of_obj.reduce((stored, item) => {
if(!stored[item.emp_name] || stored[item.emp_name].date < item.date)
stored[item.emp_name] = item;
return stored;
}, {});
Object.values(max_dates).map(item => item.max = true)
Upvotes: 1
Reputation: 2488
let arr_of_obj = [{
emp_name: 'Mark',
date: new Date('2018/05/01')
},
{
emp_name: 'Mark',
date: new Date('2018/05/02')
},
{
emp_name: 'John',
date: new Date('2018/04/05')
},
{
emp_name: 'John',
date: new Date('2018/03/22')
},
{
emp_name: 'Mark',
date: new Date('2018/05/06')
}
];
console.log('initial array', arr_of_obj);
const max_items = arr_of_obj.map((o, i) => {
return {
ord: i,
emp_name: o.emp_name,
date: o.date
};
}).sort((a, b) => b.date - a.date).reduce((l, r) => {
if (!Array.isArray(l)) {
if (l.emp_name === r.emp_name) return l.date > r.date ? [l] : [r];
return [l, r];
}
const last = l.slice(-1)[0];
if (last.emp_name === r.emp_name) {
if (last.date < r.date) l[l.length - 1] = r;
} else l.push(r);
return l;
});
max_items.forEach(o => arr_of_obj[o.ord] = {
emp_name: o.emp_name,
date: o.date,
max: true
});
console.log('max items', max_items);
console.log('updated array', arr_of_obj);
Creates a second array that only contains the max items, along with their original array index.
[
{ ord: 4, emp_name: 'Mark', date: 2018-05-06T07:00:00.000Z },
{ ord: 2, emp_name: 'John', date: 2018-04-05T07:00:00.000Z }
]
Lastly iterate over it and update the array indexes in the original array. This preserves order of the original. I would also recommend breaking out the reduce function into a separate function for readability, but it works for this example.
Upvotes: 0
Reputation: 61
You can sort the array base on the date then mark the max. see my code
let arr_of_obj = [{emp_name:'Mark',date:new Date('2018/05/01')},
{emp_name:'Mark',date:new Date('2018/05/02')},
{emp_name:'John',date:new Date('2018/04/05')},
{emp_name:'John',date:new Date('2018/03/22')},
{emp_name:'Mark',date:new Date('2018/05/06')}];
let arr = arr_of_obj.slice().sort((a,b) => new Date(b.date) - new Date(a.date));
let mark = arr[arr.findIndex(p => p.emp_name === 'Mark')];
let john = arr[arr.findIndex(p => p.emp_name === 'John')];
let new_array = arr_of_obj.map(obj => obj.date === mark.date || obj.date === john.date ? {...obj, max: true} : obj);
Upvotes: 1
Reputation: 48793
const arr = [{emp_name:'Mark',date:new Date('2018/05/01')},
{emp_name:'Mark',date:new Date('2018/05/02')},
{emp_name:'John',date:new Date('2018/04/05')},
{emp_name:'John',date:new Date('2018/03/22')},
{emp_name:'Mark',date:new Date('2018/05/06')}]
const max_map = {}; // Holds map of (name => obj_with_max_date) items,
arr.forEach((item, i)=> {
// Checking whether emp_name is not stored in map, then store the object
// and if `emp_name` is already exists in map, comparing `date` fields
if (!max_map[item.emp_name] || max_map[item.emp_name].date < arr[i].date) {
max_map[item.emp_name] = arr[i];
}
});
// Traversing the map and assigning flags for each emp_name
Object.keys(max_map).forEach( name => {
max_map[name].max = true;
});
Upvotes: 1