Yura
Yura

Reputation: 33

How to get object with max value of 'number' for each distinct 'type' from array of objects?

I have an array of objects:

const myArr = [
    { type: 'one', number: 1, fiedld: 'aaa' },
    { type: 'one', number: 2, field: 'bb' },
    { type: 'two', number: 2, field: 'xxx' }, 
    { type: 'two', number: 1, field: 'zz' }, 
    { type: 'two', number: 3, field: 'y' }
]

And I want to get objects with max value of number for each type. So expected result is:

const newArr= [
           { type: 'one', number: 2, field: 'bb' }, 
           { type: 'two', number: 3, field: 'y' }
]

My current solution is:

sortByFields (field1, field2) {
    return ((x, y) => {
        return (
            (x[field1] > y[field1]) - (y[field1] > x[field1])
            || (x[field2] > y[field2]) - (y[field2] > x[field2])
        );
    })
}

myArr.sort(this.sortByFields('type', 'number'));
let newArr = [];
for (let i = 0; i < myArr.length - 1; i++) {
    if (myArr[i].type !== myArr[i + 1].type) {
        newArr.push(myArr[i]);
    }
    if (i === myArr.length - 2) {
        newArr.push(myArr[i + 1]);
    }
}

I'm beginner in JS, but I know that it can be done in more proper way.

Upvotes: 3

Views: 608

Answers (3)

Mikhail Shabrikov
Mikhail Shabrikov

Reputation: 8509

Solution with chaining of LoDash methods (need LoDash library):

const myArr = [{ type: 'one', number: 1, field: 'aaa' },
               { type: 'one', number: 2, field: 'bb' },
               { type: 'two', number: 2, field: 'xxx' }, 
               { type: 'two', number: 1, field: 'zz' }, 
               { type: 'two', number: 3, field: 'y' }
    ];

const result = _(myArr)
  .groupBy('type')
  .map(_.unary(_.partialRight(_.maxBy, 'number')))
  .value()

console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>

Upvotes: 0

Nina Scholz
Nina Scholz

Reputation: 386604

You copuld use a straight forward approach with a hash table.

var array = [{ type: 'one', number: 1, fiedld: 'aaa' }, { type: 'one', number: 2, field: 'bb' }, { type: 'two', number: 2, field: 'xxx' }, { type: 'two', number: 1, field: 'zz' }, { type: 'two', number: 3, field: 'y' }],
    indices = Object.create(null),
    result = array.reduce(function (r, a) {
        if (!(a.type in indices)) {
            indices[a.type] = r.push(a) - 1;
            return r;
        }
        if (a.number > r[indices[a.type]].number) {
            r[indices[a.type]] = a;
        }
        return r;
    }, []);
    
console.log(result)

Upvotes: 0

Nenad Vracar
Nenad Vracar

Reputation: 122047

You can use reduce() to make one object with keys for each type and then use Object.values to get array of objects.

const myArr = [{ type: 'one', number: 1, fiedld: 'aaa' },{ type: 'one', number: 2, field: 'bb' },{ type: 'two', number: 2, field: 'xxx' }, { type: 'two', number: 1, field: 'zz' }, { type: 'two', number: 3, field: 'y' }]

var result = Object.values(myArr.reduce(function(r, e) {
  if(!r[e.type]) r[e.type] = e;
  else if(e.number > r[e.type].number) r[e.type] = e;
  return r;
}, {}))

console.log(result)

Upvotes: 3

Related Questions