'How to get unique values from Object Array Javascript

So I have an object array that as follows:

var array = [
    {name:"Joe", date:'2018-07-01', amt:250 },
    {name:"Mars", date:'2018-07-01', amt:250 },
    {name:"Joe", date:'2018-07-02', amt:250 },
    {name:"Saturn", date:'2018-07-01', amt:250 },
    {name:"Joe", date:'2018-07-02', amt:250 },
    {name:"Jupiter", date:'2018-07-01', amt:250 },
]

I want to filter data depending if the name, amount and date has duplicate. This one doesn't filter even a duplicate name.

var unique = array.filter((v, i, a) =>{ return a.indexOf(v) === i});

How can I filter duplicate for this one based on name, amount and date?



Solution 1:[1]

Just try this:

     var array = [
        {name:"Joe", date:'2018-07-01', amt:250 },
        {name:"Mars", date:'2018-07-01', amt:250 },
        {name:"Joe", date:'2018-07-02', amt:250 },
        {name:"Saturn", date:'2018-07-01', amt:250 },
        {name:"Joe", date:'2018-07-02', amt:250 },
        {name:"Jupiter", date:'2018-07-01', amt:250 },
    ]

    var unique = Array.from(new Set(array.map(JSON.stringify))).map(JSON.parse);
    
    console.log(unique)

Solution 2:[2]

A solution with Array.prototype.filter and Set:

var data=[{name:"Joe",date:"2018-07-01",amt:250},{name:"Mars",date:"2018-07-01",amt:250},{name:"Joe",date:"2018-07-02",amt:250},{name:"Saturn",date:"2018-07-01",amt:250},{name:"Joe",date:"2018-07-02",amt:250},{name:"Jupiter",date:"2018-07-01",amt:250}];

var filtered = data.filter(function({name, date, amt}) {
    var key = `${name}${date}${amt}`;
    return !this.has(key) && this.add(key);
}, new Set);

console.log(filtered);

Solution 3:[3]

var array = [
    {name:"Joe", date:'2018-07-01', amt:250 },
    {name:"Mars", date:'2018-07-01', amt:250 },
    {name:"Joe", date:'2018-07-02', amt:250 },
    {name:"Saturn", date:'2018-07-01', amt:250 },
    {name:"Joe", date:'2018-07-02', amt:250 },
    {name:"Jupiter", date:'2018-07-01', amt:250 },
]

let answer = [];

array.forEach(x => {
  if(!answer.some(y => JSON.stringify(y) === JSON.stringify(x))){
    answer.push(x)
  }
})

console.log(answer)

An alternative solution. You can use Array#forEach, Array#some, JSON.stringify to achieve what you want

Solution 4:[4]

You can use https://lodash.com/ library

If you need unique by only one value:

array = _.uniqWith(array, function(arrVal, othVal) {
    return arrVal.name == othVal.name || arrVal.date == othVal.date || arrVal.amt == othVal.amt;
}) 
console.log(array);

And if you need to remove unique by complete object:

array = _.uniq(array);
console.log(array);

Solution 5:[5]

This code shows the duplicates in your console. If you want to print everything except the duplicates swap the return true with return false and the return false with return true.

var orders = [
    {name:"Joe", date:'2018-07-01', amt:250 },
    {name:"Mars", date:'2018-07-01', amt:250 },
    {name:"Joe", date:'2018-07-02', amt:250 },
    {name:"Saturn", date:'2018-07-01', amt:250 },
    {name:"Joe", date:'2018-07-02', amt:250 },
    {name:"Jupiter", date:'2018-07-01', amt:250 },
];

orders = orders.filter( (order, index) => {

  // iterate over the array to check for possible duplicates
  // iterating over the items we already checked isn't necessary so we start at index+1
  for( let i = index+1; i<orders.length; i++ ){
    if(
      orders[i].name === order.name
      && orders[i].date === order.date
      && orders[i].amt === order.amt
    ){
     // just logging this stuff so you can see what happens
     console.log( `${index} is a duplicate of ${i}` );
     // if a duplicate is found return true to the filter function
     return true; 
    }
  }
  // if no duplication is found return false to the filter function
  return false;
  
}); // end filter 

// log the result to the console
console.log(orders);

Solution 6:[6]

Given your origin array:

var array = [
    {name:"Joe", date:'2018-07-01', amt:250 },
    {name:"Mars", date:'2018-07-01', amt:250 },
    {name:"Joe", date:'2018-07-02', amt:250 },
    {name:"Saturn", date:'2018-07-01', amt:250 },
    {name:"Joe", date:'2018-07-02', amt:250 },
    {name:"Jupiter", date:'2018-07-01', amt:250 }
];

You need a function to determine the criteria you want to check to make your object comparable with anothers.

UPDATE

Such a function could be an hash function that you should write to create a unique key to identify your objects and compare each other.

The proper hash function should return the same value if called with objects that have the same composed key.

In your case, when 2 objects have name, date and amount with the same value, the hash function is supposed to return the same value.

So you can directly compare hash values instead of objects.

In the case you asked for, all the values concurred to the filter, and here is a very trivial example of such a function, that is not proper an "hash" as the output is variable (should produce a fixed length value instead):

function objectHash (obj) {
    return Object.values(obj).reduce((a, b) => {
        a += b;
        return a;
    }, '');
}

Now, you are now able to easily and properly compare items in your array in order to filter duplication.

var arrayMap = array.reduce((acc, item) => {
    var hash = objectHash(item);
    if (typeof acc[hash] === 'undefined') {
        acc[hash] = Object.assign({}, item);
    }
    return acc;
}, {})

Then you have an object with unique key values, and to have back your unique array:

 var uniqueArray = Object.values(arrayMap);

Now you have your data.

Solution 7:[7]

This works by requiring by filtering the array such that the only elements included are those whose first matching entry in the original array (aliased as a) has the same index as the element currently being examined:

let uniq = array.filter(({name, date, amount}, index, a) =>
               a.findIndex(e => name === e.name &&
                                date === e.date &&
                              amount === e.amount) === index);

Solution 8:[8]

Here is how I would have done it:

const array = [
    {name:"Joe", date:'2018-07-01', amt:250 },
    {name:"Mars", date:'2018-07-01', amt:250 },
    {name:"Joe", date:'2018-07-02', amt:250 },
    {name:"Saturn", date:'2018-07-01', amt:250 },
    {name:"Joe", date:'2018-07-02', amt:250 },
    {name:"Jupiter", date:'2018-07-01', amt:250 },
];

function uniqueBy(arr, key, $some = false) {
  if (key instanceof Array) {
    if ($some) {
      return key.reduce(uniqueBy, arr);
    } else {
      const fnUnique = (obj) =>
        key.reduce((a, k) => `${a}-${obj[k]}`, '');
      return Object.values(arr.reduce((a, v) => {
          const key = fnUnique(v)
          return a[key] === undefined ? (a[key] = v, a) : a;
      }, {}));
  }
}
return Object.values(arr.reduce((a, v) => (a[v[key]] === undefined ? (a[v[key]] = v, a) : a), {}));
}

// print unique objects based on the given fields
console.log(uniqueBy(array, ['name', 'date', 'amt']));

// print unique objects based on any unique value in any given fields
console.log(uniqueBy(array, ['name', 'date', 'amt'], true));

This only cares about the given fields and thus you can get less results if you had objects that were duplicates but had other properties that were not interesting.

Passing true as the third argument treats the fields as unique themselves. Thus the result will only have objects where all the fields are unique and thus since the amount is the same you end up with one element.

Solution 9:[9]

Code to Filter unique id with name

{id: 555, name: "Sales", person: "Jordan" },
{id: 555, name: "Sales", person: "Bob" },
{id: 555, name: "Sales", person: "John" },
{id: 777, name: "Accounts Payable", person: "Rhoda" },
{id: 777, name: "Accounts Payable", person: "Harry" },
{id: 888, name: "IT", person: "Joe" },
{id: 888, name: "IT", person: "Jake" },
];
var unique = [];
var tempArr = [];
data.forEach((value, index) => {
    if (unique.indexOf(value.name) === -1) {
        unique.push(value.name);
        tempArr.push(value.id);
    }
});
console.log('Unique Ids', tempArr);

Solution 10:[10]

A simple and generic solution using typescript and building upon the accepted answer above. This returns an array of unique objects of the same type as the original array, checking all properties, and should work for all types of objects. It also works if the order of the properties is different in different items (in which case the JSON.stringify approach fails).

getDistinctObjectArray<T>(arr: T[]) {
    return arr.filter((item, ix, self) =>
      self.findIndex(f => 
        Object.keys(item).every(k => f[k] === item[k])) === ix);
  }

It works by filtering the array: for each item, it searches the array for the first occurrence of an item which has the same values for all its properties. If the index of the found item is not the same index as the current item, it is removed from the list.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 mplungjan
Solution 2 Leonid Pyrlia
Solution 3 Isaac
Solution 4
Solution 5 Rob Monhemius
Solution 6
Solution 7 Alnitak
Solution 8
Solution 9 Shridhar Sagari
Solution 10