JavaScript: Remove duplicates of objects sharing same property value

48,020

Solution 1

You can use underscore for this:

//by size:
var uSize = _.uniqBy(arrayWithDuplicates, function(p){ return p.size; });

//by custom.price;
var uPrice = _.uniqBy(arrayWithDuplicates, function(p){ return p.custom.price; });

Solution 2

This function removes duplicate values from an array by returning a new one.

function removeDuplicatesBy(keyFn, array) {
    var mySet = new Set();
    return array.filter(function(x) {
        var key = keyFn(x), isNew = !mySet.has(key);
        if (isNew) mySet.add(key);
        return isNew;
    });
}

var values = [{color: "red"}, {color: "blue"}, {color: "red", number: 2}];
var withoutDuplicates = removeDuplicatesBy(x => x.color, values);
console.log(withoutDuplicates); // [{"color": "red"}, {"color": "blue"}]

So you could use it like

var arr = removeDuplicatesBy(x => x.custom.price, yourArrayWithDuplicates);

Solution 3

I don't think there's a built-in function in Angular, but it isn't hard to create one:

function removeDuplicates(originalArray, objKey) {
  var trimmedArray = [];
  var values = [];
  var value;

  for(var i = 0; i < originalArray.length; i++) {
    value = originalArray[i][objKey];

    if(values.indexOf(value) === -1) {
      trimmedArray.push(originalArray[i]);
      values.push(value);
    }
  }

  return trimmedArray;

}

Usage:

removeDuplicates(arrayWithDuplicates, 'size');

Returns:

[
    {
        "color": "red",
        "size": "small"
    },
    {
        "color": "blue",
        "size": "medium"
    },
    {
        "color": "red",
        "size": "large"
    }
]

And

removeDuplicates(arrayWithDuplicates, 'color');

Returns:

[
    {
        "color": "red",
        "size": "small"
    },
    {
        "color": "green",
        "size": "small"
    },
    {
        "color": "blue",
        "size": "medium"
    }
]

Solution 4

Use Array.filter(), keeping track of values by using an Object as a hash, and filtering out any items whose value is already contained in the hash.

function trim(arr, key) {
    var values = {};
    return arr.filter(function(item){
        var val = item[key];
        var exists = values[val];
        values[val] = true;
        return !exists;
    });
}

Solution 5

You can use lodash to remove duplicate objects:

 import * as _ from 'lodash';
  _.uniqBy(data, 'id');

Here 'id' is your unique identifier

Share:
48,020
Lauren F
Author by

Lauren F

Updated on May 29, 2020

Comments

  • Lauren F
    Lauren F almost 4 years

    I have an array of objects that I would like to trim down based on a specific key:value pair. I want to create an array that includes only one object per this specific key:value pair. It doesn't necessarily matter which object of the duplicates is copied to the new array.

    For example, I want to trim based on the price property of arrayWithDuplicates, creating a new array that only includes one of each value:

    var arrayWithDuplicates = [
      {"color":"red", 
        "size": "small",
        "custom": {
          "inStock": true,
          "price": 10
        }
      },
      {"color":"green", 
        "size": "small",
        "custom": {
          "inStock": true,
          "price": 30
        }
      },
      {"color":"blue", 
        "size": "medium",
        "custom": {
          "inStock": true,
          "price": 30
        }
      },
      {"color":"red", 
        "size": "large",
        "custom": {
          "inStock": true,
          "price": 20
        }
      }
    ];
    

    Would become:

    var trimmedArray = [
      {"color":"red", 
        "size": "small",
        "custom": {
          "inStock": true,
          "price": 10
        }
      },
      {"color":"green", 
        "size": "small",
        "custom": {
          "inStock": true,
          "price": 30
        }
      },
      {"color":"red", 
        "size": "large",
        "custom": {
          "inStock": true,
          "price": 20
        }
      }
    ];
    

    Is there a JavaScript or Angular function that would loop through and do this?

    EDIT: The property to filter on is nested within another property.