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 name
d 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: