Keep object in array which has the highest value but remove all the objects that have duplicate value

Viewed 682

I have an array of objects. I want to keep the object which has the highest value but remove any duplicates.

For example, in the following array of objects, I want to remove the object that has a duplicate price and keep the one with the highest value. -

const data = [{
    "title": "The Little Prince",
    "price": 49,
    "value": 20
  },
  {
    "title": "Watchmen",
    "price": 49,
    "value": "40"
  }
]

/**
const desiredOutput = [
  {
     "title":"Watchmen",
     "price": 49,
     "value": 40
  }
] 
**/

Here's my code but it doesn't remove the object with the same price and outputs the same array -

const data = [{
    "title": "The Little Prince",
    "price": 49,
    "value": 20
  },
  {
    "title": "Watchmen",
    "price": 49,
    "value": "40"
  }
]

const removeDuplicatePrice = plans => {
  const prices = [];
  const updatedBooks = plans.filter(el => {
    const matchingRack = prices.find(
      element =>
      element.price === el.price
    );
    let {
      price,
      value
    } = el;

    if (!matchingRack) {
      prices.push({
        price,
        value
      });
      return true;
    }

    if (el.value > matchingRack.value) {
      matchingRack.value = el.value;
      return true;
    }
    return false;
  });

  return updatedBooks;
};

console.log(removeDuplicatePrice(data));

2 Answers

Using .reduce(), you can index by the price property. The price number in the object will hold the current largest value object for that given price. If your current object you are iterated on has a higher value, you can update the indexed value for that price to hold the new object. You can get the Object.values() of your accumulated object to get the unique objects.

See example below:

const data = [{ "title": "The Little Prince", "price": 49, "value": 20 }, { "title": "Watchmen", "price": 49, "value": 40 } ];

const res = Object.values(data.reduce((acc, obj) => {
  const curr = acc[obj.price];
  acc[obj.price] = curr ? (curr.value < obj.value ? obj : curr) : obj;
  return acc;
}, {}));

console.log(res);

Or using an ES6 Map might be a more appropriate option to use with .reduce():

const data = [{ "title": "The Little Prince", "price": 49, "value": 20 }, { "title": "Watchmen", "price": 49, "value": 40 } ];

const res = Array.from(data.reduce((m, obj) => {
  const curr = m.get(obj.price);
  return m.set(obj.price, curr ? (curr.value < obj.value ? obj : curr) : obj);
}, new Map).values());

console.log(res);

You can use array.reduce to remove duplicates from current array:

const data = [{
    "title": "The Little Prince",
    "price": 49,
    "value": "20"
  },
  {
    "title": "Watchmen",
    "price": 49,
    "value": "40"
  }
]

let result = data.reduce((state, current) => {
   let prevIndex = state.findIndex(x => x.price === current.price);
   if(prevIndex === -1){
       state.push(current);
   }
   else if(state[prevIndex].value < current.value){
       state[prevIndex] = current;
   }
   return state;
}, []);

console.log(result);

Related