0

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.

1

5 Answers 5

1

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)

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

Comments

1

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

Comments

0

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.

Comments

0

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

Comments

0

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

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.