Reputation: 11
I've scoured through many posts and have been working on this problem for too long. The gist is that I want to filter an array if there are duplicate object id's and return the object with the lower value or "val", otherwise return the original element.
Start with:
**edited input for clarification
let input = [
{"id": 1, "val": 3},
{"id": 2, "val": 1},
{"id": 3, "val": 4},
{"id": 1, "val": 0}
]
function removeDuplicates(array, propertyName) {
// where propertyName is "id"
}
The result of the function should be:
[
{"id": 1, "val": 0},
{"id": 2, "val": 1},
{"id": 3, "val": 4}
]
Upvotes: 0
Views: 2094
Reputation: 7673
You can use Array.reduce
to build a new hash out of the lowest values, then just return the values of that hash.
var input = [
{"id": 1, "val": 0},
{"id": 2, "val": 0},
{"id": 3, "val": 0},
{"id": 1, "val": 1}
];
function minFromArray(ar) {
//Object.values returns the values of a hash as an array.
return Object.values(ar.reduce(function(acc, obj){
//If this is the first instance of the ID, or the value is lower than the existing
if (typeof(acc[obj['id']]) == 'undefined' || obj['val'] < acc[obj['id']]) {
acc[obj['id']] = obj;
}
return acc;
}, {}));
}
console.log(minFromArray(input));
Upvotes: 0
Reputation: 490
The most efficient approach is to simply use a temp object to store all the objects in the array with the ids as object keys, since object key can't be duplicate, multiple occurrence will simply override each other till finally you will just have to convert the object back into an array using Object.values(obj)
.
var input = [
{"id": 1, "val": 0},
{"id": 2, "val": 0},
{"id": 3, "val": 0},
{"id": 1, "val": 1}
];
function removeDuplicates(array, propertyName) {
var tmp = {};
array.forEach(function (v) {
if (tmp[v[propertyName]] == null) {
tmp[v[propertyName]] = v;
} else if (v.val < tmp[v[propertyName]].val)
tmp[v[propertyName]] = v;
}
});
return Object.values(tmp);
}
Use this:
removeDuplicates(input, "id");
To return the following:
[
{"id": 1, "val": 0},
{"id": 2, "val": 0},
{"id": 3, "val": 0}
]
Upvotes: 0
Reputation: 4720
Use .filter
and .map
:
inputs
.filter(object => object.id == propertyValue) // get only the objects you want
.map(object => object.val) // convert each object to it's value
.sort() // sort it
[0] // and get the first (meaning smallest) element
Upvotes: 0
Reputation: 5472
You can use reduce
and then check in the accumulator if current value is smaller than one you have already saved.
let input = [
{"id": 1, "val": 0},
{"id": 2, "val": 0},
{"id": 3, "val": 0},
{"id": 1, "val": 1}
]
function removeDuplicates(array, propertyName) {
return array.reduce((acc, cv) => {
if (acc.hasOwnProperty(cv[propertyName])) {
if (cv.val < acc[cv[propertyName]].val)
acc[cv[propertyName]] = cv;
} else
acc[cv[propertyName]] = cv;
return acc;
}, {});
}
console.log(removeDuplicates(input,"id"))
Upvotes: 0
Reputation: 171679
A very common approach to such issues is to create a temporary object that uses the common property as keys and a full object as values.
Once you loop through the data array once and build the object then it is a simple process to put the values into resultant array
let input = [
{"id": 1, "val": 0},
{"id": 2, "val": 0},
{"id": 3, "val": 0},
{"id": 1, "val": 1}
]
let tmp = {}
input.forEach(o=> {
tmp[o.id] = tmp[o.id] || o;
// assign lower value if applicable
if( o.val < tmp[o.id].val){
tmp[o.id].val = o.val;
}
});
let res = Object.values(tmp);
console.log(res);
Upvotes: 3