Anastasiia
Anastasiia

Reputation: 11

An array of objects is returned to me. How to return an array of objects where only the unique groups with the maximum value will remain?

[
{"score": 99, "group":"1"},
{"score": 90, "group":"2"},
{"score":"10", "group":"1"},
{"score":"10",      "group":"2"},
]
 

I work with TypeOrm now and want to filter data.

Expected array:

[
{"score": 99,      "group":"1"},
{"score": 90,     "group":"2"},
]

Upvotes: 0

Views: 198

Answers (5)

Moritz Ringler
Moritz Ringler

Reputation: 15816

For fun, here is another version:

const data = [
    {"score": 99, "group":"1"},
    {"score": 90, "group":"2"},
    {"score": 10, "group":"1"},
    {"score": 10, "group":"2"},
]

const maxByGroup = {}
for(const entry of data){
  const max = maxByGroup[entry.group]
  maxByGroup[entry.group] = max && max.score >= entry.score ? max : entry
}
const result = Object.values(maxByGroup)

console.log(result)

Probably the simplest way to do it, arguably the easiest to read, happens to be the fastest, too

Upvotes: 0

pilchard
pilchard

Reputation: 12919

You can simply group by group keeping only the objects with the highest score. Here accumulating into a Map and then spreading the iterator returned by Map.values() as the result.

const input = [{ score: 99, group: '1' }, { score: 90, group: '2' }, { score: '10', group: '1' }, { score: '10', group: '2' },];

const reduced = input.reduce(
  (a, o) =>
    !a.has(o.group) || o.score > a.get(o.group)?.score
      ? a.set(o.group, { ...o })
      : a,
  new Map()
);

const result = [...reduced.values()];

console.log(result);

Upvotes: 0

Nina Scholz
Nina Scholz

Reputation: 386604

You could take a single loop approach with an object for keeping the groups.

const
    data = [{ score: 99, group: "1" }, { score: 90, group: "2" }, { score: 10, group: "1" }, { score: 10, group: "2" }],
    maxScore = Object.values(data.reduce((r, o) => {
        if (!r[o.group] || r[o.group].score < o.score) r[o.group] = o;
        return r;
    }, {}));
    
console.log(maxScore);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Upvotes: 0

Andrew Parks
Andrew Parks

Reputation: 8087

const data = [
{"score": 99, "group":"1"},
{"score": 90, "group":"2"},
{"score": 10, "group":"1"},
{"score": 10, "group":"2"}]

const result = [...new Set(data.map(i=>i.group))] // get unique group ids
  .map(g=>data.filter(({group})=>g===group) // find members of each group 
  .sort(({score:a},{score:b})=>a-b).pop()) // find the one with highest score

console.log(result)

If your data includes scores that are strings instead of numbers, change a-b to (+a)-(+b) to coerce the strings to numbers.

Upvotes: 1

CallSign-Filter
CallSign-Filter

Reputation: 1301

I would use Lodash in this case

function maxGroups() {
let arr = [
    {"score": 99, "group":"1"},
    {"score": 90, "group":"2"},
    {"score": 10, "group":"1"},
    {"score": 10, "group":"2"},
]

let newArr = _.groupBy(arr, "group")
let result = _.map(newArr, i => (_.maxBy(i, 'score')));
console.dir(result)

}

Upvotes: 0

Related Questions