0

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}]
4
  • is the data sorted? does the data have only one latest date? Commented May 22, 2018 at 14:27
  • Data wasn't sorted and object doesn't contain more than one date or emp_name property. Commented May 22, 2018 at 14:31
  • and what does not work? Commented May 22, 2018 at 14:33
  • I need an efficient way to update records using map or something inbuilt methods. Commented May 22, 2018 at 14:35

4 Answers 4

1
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;
});

DEMO

Sign up to request clarification or add additional context in comments.

5 Comments

just a hint, you could take instead of the index just the object itself for comparison and later setting the flag.
then you could iterate just over the values, no keys needed.
I appreciate your efforts @Engineer
@NinaScholz. Is there any better solution? If you've let us know.
for the flags: Object.values(max_map).forEach(o => o.max = true);
1

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);

3 Comments

The array should remains in their order.
Then you need to swipe the one marked with max with the original one in the arr_of_obj. This can be achieved with map function.
updated the code to reflect the ordering constraint.
1

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)

Comments

0

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.