Home > Mobile >  Compare objects within an array and create a new array without duplicates
Compare objects within an array and create a new array without duplicates

Time:05-04

I've an object array:

[{name: "John", age: "34"}, {name: "Ace", age: "14"}, {name: "John", age: "45"}, {name: "Harry", age: "11"}]

I want to compare the object within array by name. If the duplicate name exist, I should compare the age and keep only that object who age is greater. So expected output should be:

[{name: "Ace", age: "14"}, {name: "John", age: "45"}, {name: "Harry", age: "11"}]

I am new to javascript/typescript and couldn't find any optimal solution for a problem, I hope I am able to explain my problem clearly. Thanks.

CodePudding user response:

The next provided approach uses reduce and creates in a first step just an index/map of items of highest age which are each unique by name. Thus one could use the temporary state of the programmatically built result as lookup for already existing named items.

Within a second step one would retrieve the array of unique named items of highest age by passing such an index to Object.values.

function collectHighestAgeItemOfSameName(result, item) {
  const { name, age } = item;
  if (
    !(name in result) ||
    Number(result[name].age) < Number(age)
  ) {
    result[name] = item;
  }
  return result;
}

const sampleData = [{
  name: "John",
  age: "34"
}, {
  name: "Ace",
  age: "14"
}, {
  name: "Harry",
  age: "9"
}, {
  name: "John",
  age: "45"
}, {
  name: "Harry",
  age: "11"
}, {
  name: "Ace",
  age: "13"
}];

console.log(
  'reduced index of unique person items of highest age ...',
  sampleData
    .reduce(collectHighestAgeItemOfSameName, {})
)
console.log(
  'array of unique person items of highest age ...',
  Object
    .values(
      sampleData
        .reduce(collectHighestAgeItemOfSameName, {})
    )
)
.as-console-wrapper { min-height: 100%!important; top: 0; }

CodePudding user response:

Maybe something like that

const obj = [{ name: "John", age: "34" }, { name: "Ace", age: "14" }, { name: "John", age: "45" }, { name: "Harry", age: "11" }];
const objCopy = JSON.parse(JSON.stringify(obj))

const res = objCopy.reduce((acc, obj) => {
  const personExist = acc.find(({ name }) => name === obj.name);
  if (personExist) {
    if (parseInt(obj.age, 10) > parseInt(personExist.age, 10)) {
        personExist.age = obj.age;
    }
  } else {
    acc.push(obj);
  }
  return acc;
}, []);

console.log({ res });
.as-console-wrapper { min-height: 100%!important; top: 0; }

CodePudding user response:

try this

var objArr=...your json object;

var newArr = [];
var arr = groupBy(objArr, "name");

$.each(arr, function (key) {
  var maxAge = 0;
  var maxItem;
  arr[key].forEach((element) => {
    if (element.age > maxAge) {
      maxAge = element.age;
      maxItem = element;
    }
  });
  newArr.push(maxItem);
});

groupby

var groupBy = function (xs, key) {
  return xs.reduce(function (rv, x) {
    (rv[x[key]] = rv[x[key]] || []).push(x);
    return rv;
  }, {});
};

CodePudding user response:

This works basically the same as @PeterSeliger's fine and upvote-worthy answer, except it uses a Map object which is nice because Map.set returns the Map object, allowing you to return it as the accumulator for the next iteration of the reduce function.

const data = [{name: "John", age: "34"}, {name: "Ace", age: "14"}, {name: "John", age: "45"}, {name: "Harry", age: "11"}];

const res = [...data.reduce(
  (acc, val) =>
     (acc.get(val.name)?.age ?? -1) >=  val.age ?
      acc :
      acc.set(val.name, val),
  new Map()
).values()];

console.log(JSON.stringify( res ));
.as-console-wrapper { min-height: 100%!important; top: 0; }

Other references:

  1. Unary plus ( )
  2. Optional chaining (?.)
  3. Nullish coalescing operator (??)
  4. Conditional (ternary) operator
  5. Array.prototype.reduce()
  6. Spread syntax (...)
  • Related