simplyketchup
simplyketchup

Reputation: 11

Filter an array to remove duplicates in JS

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

Answers (5)

Ben Hull
Ben Hull

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

Ori Shalom
Ori Shalom

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

AskYous
AskYous

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

JohanP
JohanP

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

charlietfl
charlietfl

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

Related Questions