Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I remove an object from array of objects based on max value in javascript

I've got an array of objects that looks like this:

[ { person: 'Fred', scoreTotal: 29 },
{ person: 'Alice', scoreTotal: 34 },
{ person: 'Alice', scoreTotal: 22 },
{ person: 'Mary', scoreTotal: 14 },
{ person: 'Bob', scoreTotal: 33 },
{ person: 'Bob', scoreTotal: 13 },
{ person: 'Bob', scoreTotal: 22 },
{ person: 'Joe', scoreTotal: 28 }]

and where there are multiple objects for a given person -> I want to keep the top "X". For example:

a. top 1 result for a person Result would look like this:

    [ { person: 'Fred', scoreTotal: 29 },
    { person: 'Alice', scoreTotal: 34 },
    { person: 'Mary', scoreTotal: 14 },
    { person: 'Bob', scoreTotal: 33 },
    { person: 'Joe', scoreTotal: 28 }]

b. top 2 results for a person Result would look like this:

   [ { person: 'Fred', scoreTotal: 29 },
  { person: 'Alice', scoreTotal: 34 },
   { person: 'Alice', scoreTotal: 22 },
   { person: 'Mary', scoreTotal: 14 },
   { person: 'Bob', scoreTotal: 33 },
   { person: 'Bob', scoreTotal: 22 },
   { person: 'Joe', scoreTotal: 28 }]

Is there a way to achieve this using something like Lodash?

I think I'm heading in the right direction with this but not quite there yet:

for (var i = 0; i < t.length - 1; i++) {
if (
  t[i].golfer === t[i + 1].golfer &&
  t[i].scoreTotal < t[i + 1].scoreTotal
) {
  delete t[i];
}

}

// remove the "undefined entries"

t = t.filter(function(el) {
    return typeof el !== "undefined";
});
console.log(t);
like image 843
ajonno Avatar asked Jul 10 '18 02:07

ajonno


2 Answers

You can do this pretty simply without Underscore/Lodash. Sort the array highest to lowest by score. Then use Array.filter. As filter goes through the array keep track of how many times you see each person and start return false after the top number you want has been reached for a person.

let arr = [ { person: 'Fred', scoreTotal: 29 },{ person: 'Alice', scoreTotal: 34 },{ person: 'Alice', scoreTotal: 22 },{ person: 'Mary', scoreTotal: 14 },{ person: 'Bob', scoreTotal: 33 },{ person: 'Bob', scoreTotal: 13 },{ person: 'Bob', scoreTotal: 22 },{ person: 'Joe', scoreTotal: 28 }]

function filterTop(arr, top) {
    let counts = {}
    return [...arr].sort((a, b) => b.scoreTotal - a.scoreTotal)
    .filter(score => (counts[score.person] = (counts[score.person] || 0) +1 ) <= top)
}


console.log(filterTop(arr, 1))
console.log(filterTop(arr, 2))
like image 97
Mark Avatar answered Oct 24 '22 05:10

Mark


Using only ES6, you can use 2 reduces. First is to group the arrays. the second is to get the number of top per group.

let arr = [{"person":"Fred","scoreTotal":29},{"person":"Alice","scoreTotal":34},{"person":"Alice","scoreTotal":22},{"person":"Mary","scoreTotal":14},{"person":"Bob","scoreTotal":33},{"person":"Bob","scoreTotal":13},{"person":"Bob","scoreTotal":22},{"person":"Joe","scoreTotal":28}];

let getTop = (a, t) => {                           //Parameters a = array. t = top
  return Object.values(a.reduce((c, v) => {        //Group the array using the person property
    c[v.person] = c[v.person] || [];
    c[v.person].push(v);
    return c;
  }, {})).reduce((c, v) => {
    v.sort((a, b) => b.scoreTotal - a.scoreTotal); //Sort the sub array
    c = c.concat(v.slice(0, t));                   //Add the top to accumulator
    return c;
  }, []);
}


let result1 = getTop(arr, 1); //Get top 1
let result2 = getTop(arr, 2); //Get top 2

console.log('Top 1', result1);
console.log('Top 2', result2);
like image 20
Eddie Avatar answered Oct 24 '22 05:10

Eddie