3

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

5 Answers 5

4

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>

Sign up to request clarification or add additional context in comments.

Comments

2

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);

2 Comments

what happens if I don't know my keys ? (I don't have 'id')
You'll have to create a function that makes a string hash from any object. If they're not nested and only contain primitives, it's most likely a concatenation of all properties. I'll include an example.
2

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)

1 Comment

what happens if I don't know my keys ? (I don't have 'id')
2

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);

6 Comments

what happens if I don't know my keys ? (I don't have 'id')
Because you store keys only once, { id: 1, label: 'one' }, { id: 1, label: 'one', test: 2 } will be considered duplicates
@user3297291, keys contains only ['id', 'label']. key (without s) contains different values.
What I meant is that you use the keys in the first object to base your hash on. If a later object is a superset of the first one (i.e. same label and id, but with additional properties), it will not be considered a unique object by your filter. But I might be wrong.
that is right, but it is not likely to have different property count in arrays with the same (comparable) structure.
|
1

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;}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.