Arpit
Arpit

Reputation: 1495

Remove object in Array of Objects if few key-value pair are same and another key-value are less than other object

I have this type of object

var array = [ 
 { "foo": 1, "bar": 2, "baz": 3 },
 { "foo": 1, "bar": 2, "baz": 5 },
 { "foo": 1, "bar": 2, "baz": 4 },
 { "foo": 2, "bar": 1, "baz": 3 },
 { "foo": 2, "bar": 1, "baz": 7 },
 { "foo": 1, "bar": 3, "baz": 4 } 
]

and If 'foo' and 'bar' key values are same then choose key 'baz' greater value and remove other objects.

like this

[ { "foo": 1, "bar": 2, "baz": 5 },
{ "foo": 2, "bar": 1, "baz": 7 },
{ "foo": 1, "bar": 3, "baz": 4 } ]

I tried this solution but it's not working for me. This question is not like my question.

So, what is the solution in underscore/lodash library or in javascript only.

Upvotes: 0

Views: 115

Answers (5)

slider
slider

Reputation: 12990

Another possibility is to sort the array by ascending order of foo and bar and descending order of baz and then do a reduce.

var array = [ 
 { "foo": 1, "bar": 2, "baz": 3 },
 { "foo": 1, "bar": 2, "baz": 5 },
 { "foo": 1, "bar": 2, "baz": 4 },
 { "foo": 2, "bar": 1, "baz": 3 },
 { "foo": 2, "bar": 1, "baz": 7 },
 { "foo": 1, "bar": 3, "baz": 4 } 
];

const res = array
  .sort((a, b) => a.foo - b.foo || a.bar - b.bar || b.baz - a.baz)
  .reduce((acc, curr) => {
    const prev = acc[acc.length - 1] || {};
    if (!(curr.foo === prev.foo && curr.bar === prev.bar)) acc.push(curr);
    return acc;
  }, []);

console.log(res);

Upvotes: 1

Jan
Jan

Reputation: 8141

const array = [
  { foo: 1, bar: 2, baz: 3 },
  { foo: 1, bar: 2, baz: 5 },
  { foo: 1, bar: 2, baz: 4 },
  { foo: 2, bar: 1, baz: 3 },
  { foo: 2, bar: 1, baz: 7 },
  { foo: 1, bar: 3, baz: 4 }
];

const result = array.reduce((result, obj) => {
  const resultObj = result.find(resultObj => obj.foo === resultObj.foo && obj.bar === resultObj.bar);

  if (!resultObj) {
    return [ ...result, obj ];
  }

  if (resultObj.baz > obj.baz) {
    return result;
  }

  return [ ...result.filter(obj => obj !== resultObj), obj ];
}, []);

console.log(result);

Upvotes: 0

Akrion
Akrion

Reputation: 18515

You could also do first orderBy ... then keyBy and lastly values to get what you need:

var array = [ { "foo": 1, "bar": 2, "baz": 3 }, { "foo": 1, "bar": 2, "baz": 5 }, { "foo": 1, "bar": 2, "baz": 4 }, { "foo": 2, "bar": 1, "baz": 3 }, { "foo": 2, "bar": 1, "baz": 7 }, { "foo": 1, "bar": 3, "baz": 4 } ]

const result = _.values(_.keyBy(
   _.orderBy(array, ['foo', 'bar', 'baz']), x=>`${x.foo}-${x.bar}`))

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

Or you can chain it as well via:

const result = _(array)
  .orderBy(['foo', 'bar', 'baz'])
  .keyBy(x => `${x.foo}-${x.bar}`)
  .values()
  .value()

Upvotes: 0

Ori Drori
Ori Drori

Reputation: 191976

With lodash you can group by the combination of the value of foo and baz. Then map the result, and select the object with the highest baz value in each group:

var array = [ 
 { "foo": 1, "bar": 2, "baz": 3 },
 { "foo": 1, "bar": 2, "baz": 5 },
 { "foo": 1, "bar": 2, "baz": 4 },
 { "foo": 2, "bar": 1, "baz": 3 },
 { "foo": 2, "bar": 1, "baz": 7 },
 { "foo": 1, "bar": 3, "baz": 4 } 
]

var result = _.map(
  _.groupBy(array, o => `${o.foo}-${o.bar}`),
  g => _.maxBy(g, 'baz')
)

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

With vanilla JS you can reduce the array into an object (the accumulator), using a similar convention for the accumulator key (combination of bar and baz). Whenever an object from the array, and an object stored in the accumulator have the same key, the one with the highest baz value is kept.

const array = [ 
 { "foo": 1, "bar": 2, "baz": 3 },
 { "foo": 1, "bar": 2, "baz": 5 },
 { "foo": 1, "bar": 2, "baz": 4 },
 { "foo": 2, "bar": 1, "baz": 3 },
 { "foo": 2, "bar": 1, "baz": 7 },
 { "foo": 1, "bar": 3, "baz": 4 } 
]

const result = Object.values(array.reduce((r, o) => {
  const key = `${o.foo}-${o.bar}`
  
  if(!r[key] || r[key].baz < o.baz) r[key] = o
  
  return r
}, {}))

console.log(result)

Upvotes: 1

Arpit
Arpit

Reputation: 1495

I tried this solution and it's working for me,

this is the solution

var result = ab.reduce((p,c) => {var o = p.find(e => e.foo === c.foo && e.bar === c.bar);
!!o ? o.baz = (o.baz > c.baz ? o.baz : c.baz) : p.push(c);
return p;},[]);

but I didn't understand the flow of this code. So, I decided to extend the code and tried to understand the code

So, First I read about reduce and find and extended the code

var result = ab.reduce((newArray, singleObj) => {
  var sameKeyValueObj = newArray.find(obj => {
    return obj.foo === singleObj.foo && obj.bar === singleObj.bar
  });
  sameKeyValueObj ? sameKeyValueObj.baz = (
    sameKeyValueObj.baz > singleObj.baz ? sameKeyValueObj.baz : singleObj.baz
  ) : newArray.push(singleObj);
  return newArray;
}, []);

This is an understandable solution for me now. If someone has another good solution then please tell me.

Upvotes: 0

Related Questions