Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to find duplicate values in a JavaScript array of objects, and output only unique values?

I'm learning JS. Supposing I have the below array of objects:

var family = [
  {
    name: "Mike",
    age: 10
  },
  {
    name: "Matt"
    age: 13
  },
  {
    name: "Nancy",
    age: 15
  },
  {
    name: "Adam",
    age: 22
  },
  {
    name: "Jenny",
    age: 85
  },
  {
    name: "Nancy",
    age: 2
  },
  {
    name: "Carl",
    age: 40
  }
];

Notice that Nancy is showing up twice (changing only the age). Supposing I want to output only unique names. How do I output the above array of objects, without duplicates? ES6 answers more than welcome.

Related (couldn't find a good way for usage on objects):

  • Remove Duplicates from JavaScript Array
  • Easiest way to find duplicate values in a JavaScript array

EDIT Here's what I tried. It works well with strings but I can't figure how to make it work with objects:

family.reduce((a, b) => {
  if (a.indexOf(b) < 0 ) {
    a.push(b);
  }
  return a;
},[]);
like image 640
2 revs Avatar asked Oct 06 '16 00:10

2 revs


People also ask

How do you get a list of duplicate objects in an array of objects with JavaScript?

To get a list of duplicate objects in an array of objects with JavaScript, we can use the array methods. to get an array of value entries with the same id and put them into duplicates . To do this, we get the id s of the items with the same id by calling map to get the id s into their own array.

How do you get all unique values remove duplicates in a JavaScript array?

To find a unique array and remove all the duplicates from the array in JavaScript, use the new Set() constructor and pass the array that will return the array with unique values. There are other approaches like: Using new ES6 feature: [… new Set( [1, 1, 2] )];

How do you check if an array of objects has duplicate values in JavaScript?

Using the indexOf() method In this method, what we do is that we compare the index of all the items of an array with the index of the first time that number occurs. If they don't match, that implies that the element is a duplicate. All such elements are returned in a separate array using the filter() method.

How do you find duplicate values in an array?

function checkIfArrayIsUnique(myArray) { for (var i = 0; i < myArray. length; i++) { for (var j = 0; j < myArray. length; j++) { if (i != j) { if (myArray[i] == myArray[j]) { return true; // means there are duplicate values } } } } return false; // means there are no duplicate values. }


5 Answers

You could use a Set in combination with Array#map and a spread operator ... in a single line.

Map returns an array with all names, which are going into the set initializer and then all values of the set are returned in an array.

var family = [{ name: "Mike", age: 10 }, { name: "Matt", age: 13 }, { name: "Nancy", age: 15 }, { name: "Adam", age: 22 }, { name: "Jenny", age: 85 }, { name: "Nancy", age: 2 }, { name: "Carl", age: 40 }],
    unique = [...new Set(family.map(a => a.name))];

console.log(unique);

For filtering and return only unique names, you can use Array#filter with Set.

var family = [{ name: "Mike", age: 10 }, { name: "Matt", age: 13 }, { name: "Nancy", age: 15 }, { name: "Adam", age: 22 }, { name: "Jenny", age: 85 }, { name: "Nancy", age: 2 }, { name: "Carl", age: 40 }],
    unique = family.filter((set => f => !set.has(f.name) && set.add(f.name))(new Set));

console.log(unique);
like image 198
Nina Scholz Avatar answered Oct 11 '22 10:10

Nina Scholz


The Solution

Store occurrences of name external to the loop in an object, and filter if there's been a previous occurrence.

https://jsfiddle.net/nputptbb/2/

var occurrences = {}

var filteredFamily = family.filter(function(x) {
  if (occurrences[x.name]) {
    return false;
  }
  occurrences[x.name] = true;
  return true;
})

you can also generalize this solution to a function

function filterByProperty(array, propertyName) {
  var occurrences = {}

  return array.filter(function(x) {
    var property = x[propertyName]
    if (occurrences[property]) {
      return false;
    }
    occurrences[property]] = true;
    return true;
  })
}

and use it like

var filteredFamily = filterByProperty(family, 'name')

Explanation

Don't compare objects using indexOf, which only uses the === operator between objects. The reason why your current answer doesn't work is because === in JS does not compare the objects deeply, but instead compares the references. What I mean by that you can see in the following code:

var a = { x: 1 }
var b = { x: 1 }

console.log(a === b) // false
console.log(a === a) // true

Equality will tell you if you found the same exact object, but not if you found an object with the same contents.

In this case, you can compare your object on name since it should be a unique key. So obj.name === obj.name instead of obj === obj. Moreover another problem with your code that affects its runtime and not its function is that you use an indexOf inside of your reduce. indexOf is O(n), which makes the complexity of your algorithm O(n^2). Thus, it's better to use an object, which has O(1) lookup.

like image 39
m0meni Avatar answered Oct 11 '22 10:10

m0meni


This will work fine.

const result = [1, 2, 2, 3, 3, 3, 3].reduce((x, y) => x.includes(y) ? x : [...x, y], []);

console.log(result);
like image 20
Divyanshu Rawat Avatar answered Oct 11 '22 10:10

Divyanshu Rawat


With the code you mentioned, you can try:

family.filter((item, index, array) => {
  return array.map((mapItem) => mapItem['name']).indexOf(item['name']) === index
})

Or you can have a generic function to make it work for other array of objects as well:

function printUniqueResults (arrayOfObj, key) {
  return arrayOfObj.filter((item, index, array) => {
    return array.map((mapItem) => mapItem[key]).indexOf(item[key]) === index
  })
}

and then just use printUniqueResults(family, 'name')

(FIDDLE)

like image 27
Cezar Augusto Avatar answered Oct 11 '22 10:10

Cezar Augusto


I just thought of 2 simple ways for Lodash users

Given this array:

let family = [
  {
    name: "Mike",
    age: 10
  },
  {
    name: "Matt",
    age: 13
  },
  {
    name: "Nancy",
    age: 15
  },
  {
    name: "Adam",
    age: 22
  },
  {
    name: "Jenny",
    age: 85
  },
  {
    name: "Nancy",
    age: 2
  },
  {
    name: "Carl",
    age: 40
  }
]

1. Find duplicates:

let duplicatesArr = _.difference(family, _.uniqBy(family, 'name'), 'name')

// duplicatesArr:
// [{ 
//   name: "Nancy", 
//   age: 2 
// }]

2 Find if there are duplicates, for validation purpose:

let uniqArr = _.uniqBy(family, 'name')

if (uniqArr.length === family.length) {
    // No duplicates
}

if (uniqArr.length !== family.length) {
    // Has duplicates
}
like image 38
Simon Dragsbæk Avatar answered Oct 11 '22 08:10

Simon Dragsbæk