que1326
que1326

Reputation: 2325

How to add non duplicate objects in an array in javascript?

I want to add non-duplicate objects into a new array.

var array = [
  {
    id: 1,
    label: 'one'
  },
  {
    id: 1,
    label: 'one'
  },
  {
    id: 2,
    label: 'two'
  }
];

var uniqueProducts = array.filter(function(elem, i, array) {
    return array.indexOf(elem) === i;
});

console.log('uniqueProducts', uniqueProducts);
// output: [object, object, object] 

live code

Upvotes: 3

Views: 9372

Answers (5)

kukkuz
kukkuz

Reputation: 42352

You can use reduce to extract out the unique array and the unique ids like this:

var array=[{id:1,label:"one"},{id:1,label:"one"},{id:2,label:"two"}];

var result = array.reduce(function(prev, curr) {
  if(prev.ids.indexOf(curr.id) === -1) {
    prev.array.push(curr);
    prev.ids.push(curr.id);
  }
  return prev;
}, {array: [], ids: []});

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

If you don't know the keys, you can do this - create a unique key that would help you identify duplicates - so I did this:

  1. concat the list of keys and values of the objects

  2. Now sort them for the unique key like 1|id|label|one

This handles situations when the object properties are not in order:

var array=[{id:1,label:"one"},{id:1,label:"one"},{id:2,label:"two"}];

var result = array.reduce(function(prev, curr) {
  var tracker = Object.keys(curr).concat(Object.keys(curr).map(key => curr[key])).sort().join('|');
  if(!prev.tracker[tracker]) {
    prev.array.push(curr);
    prev.tracker[tracker] = true;
  }
  return prev;
}, {array: [], tracker: {}});

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

Upvotes: 1

user3297291
user3297291

Reputation: 23382

Usually, you use an object to keep track of your unique keys. Then, you convert the object to an array of all property values.

It's best to include a unique id-like property that you can use as an identifier. If you don't have one, you need to generate it yourself using JSON.stringify or a custom method. Stringifying your object will have a downside: the order of the keys does not have to be consistent.

You could create an objectsAreEqual method with support for deep comparison, but this will slow your function down immensely.

In two steps:

var array=[{id:1,label:"one"},{id:1,label:"one"},{id:2,label:"two"}];

// Create a string representation of your object
function getHash(obj) {
   return Object.keys(obj)
     .sort() // Keys don't have to be sorted, do it manually here
     .map(function(k) {
       return k + "_" + obj[k]; // Prefix key name so {a: 1} != {b: 1}
     })
     .join("_"); // separate key-value-pairs by a _
}


function getHashBetterSolution(obj) {
  return obj.id; // Include unique ID in object and use that
};

// When using `getHashBetterSolution`:
// { '1': { id: '1', label: 'one' }, '2': /*etc.*/ }
var uniquesObj = array.reduce(function(res, cur) {
  res[getHash(cur)] = cur;
  return res;
}, {});

// Convert back to array by looping over all keys                             
var uniquesArr =  Object.keys(uniquesObj).map(function(k) {
  return uniquesObj[k];
});

console.log(uniquesArr);

// To show the hashes
console.log(uniquesObj);

Upvotes: 2

baao
baao

Reputation: 73251

I like the class based approach using es6. The example uses lodash's _.isEqual method to determine equality of objects.

var array = [{
  id: 1,
  label: 'one'
}, {
  id: 1,
  label: 'one'
}, {
  id: 2,
  label: 'two'
}];

class UniqueArray extends Array {
  constructor(array) {
    super();
    array.forEach(a => {
      if (! this.find(v => _.isEqual(v, a))) this.push(a);
    });
  }
}

var unique = new UniqueArray(array);
console.log(unique);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.16.4/lodash.min.js"></script>

Upvotes: 4

Nina Scholz
Nina Scholz

Reputation: 386654

You could use a hash table and store the found id.

var array = [{ id: 1, label: 'one' }, { id: 1, label: 'one' }, { id: 2, label: 'two' }],
    uniqueProducts = array.filter(function(elem) {
        return !this[elem.id] && (this[elem.id] = true);
    }, Object.create(null));

console.log('uniqueProducts', uniqueProducts);

Check with all properties

var array = [{ id: 1, label: 'one' }, { id: 1, label: 'one' }, { id: 2, label: 'two' }],
    keys = Object.keys(array[0]),                 // get the keys first in a fixed order
    uniqueProducts = array.filter(function(a) {
        var key = keys.map(function (k) { return a[k]; }).join('|');
        return !this[key] && (this[key] = true);
    }, Object.create(null));

console.log('uniqueProducts', uniqueProducts);

Upvotes: 2

Nenad Vracar
Nenad Vracar

Reputation: 122057

You can use Object.keys() and map() to create key for each object and filter to remove duplicates.

var array = [{
  id: 1,
  label: 'one'
}, {
  id: 1,
  label: 'one'
}, {
  id: 2,
  label: 'two'
}];

var result = array.filter(function(e) {
  var key = Object.keys(e).map(k => e[k]).join('|');
  if (!this[key]) {
    this[key] = true;
    return true;
  }
}, {});

console.log(result)

Upvotes: 2

Related Questions