- Find duplicate values in objects with Javascript
- 5 Answers 5
- Find duplicate objects in array and return new array of object with number of duplicates as a new property
- 6 Answers 6
- Find duplicate values in objects with Javascript
- 5 Answers 5
- Collect unique objects in JavaScript array
- 4 Answers 4
- To Remove Duplicates With All Identical Properties
- To Remove Objects with Duplicate Subset of Properties
Find duplicate values in objects with Javascript
I want to get the objects that have duplicate values in them and based on what values to search for. I.e , I want to get the object that has a duplicate value «name» and «age» but nog «country» so I will end up with:
array.forEach(function(name, age) < if(array.name == name || array.age == age)< console.log(the result) >>)
5 Answers 5
You can use 2 reduce . The first one is to group the array. The second one is to include only the group with more than 1 elements.
var array = [,,,,,] var result = Object.values(array.reduce((c, v) => < let k = v.name + '-' + v.Age; c[k] = c[k] || []; c[k].push(v); return c; >, <>)).reduce((c, v) => v.length > 1 ? c.concat(v) : c, []); console.log(result);
I’m a little late to the party but this might help someone who’s facing the same problem, as it is, I believe, an easier to understand solution:
const duplicates = []; array.forEach((el, i) => < array.forEach((element, index) => < if (i === index) return null; if (element.name === el.name && element.Age === el.Age) < if (!duplicates.includes(el)) duplicates.push(el); >>); >); console.log("duplicates", duplicates);
Two things might be tricky to understand:
- with forEach you can provide a second argument that will be an index. This is to make sure we don’t compare the same two array entries with each other (if (i === index) return null; -> to abort the forEach)
- !duplicates.includes («if not duplicates includes) checks before adding an element to the duplicates array if it’s already there. Since <> === <> is false in JS, this will not be a problem with «equal» objects already in the duplicates array, but will simply avoid adding the same element twice in one forEach loop
Edit: An even nicer solution would be this:
const duplicates = array .map((el, i) => < return array.find((element, index) => < if (i !== index && element.name === el.name && element.Age === el.Age) < return el >>) >) .filter(Boolean) console.log("duplicates:", duplicates)
It has no side effects and all logic is in one if statement. The filter is needed to sort out undefined instances.
Find duplicate objects in array and return new array of object with number of duplicates as a new property
And I need to go through it, find duplicates and reuturn only one object for each duplicate but with number of duplicates as a new parameter. So like this:
I can count duplicate objects based on one parameter but I don’t know how to do based on whole object. What is the best way to solve this?
6 Answers 6
You can do it with a combination of .map on the original array and searching through the items of the newly formed array with .find .
let arrayOfObjects = [ < Name: "Apple", Type: "Fruit" >, < Name: "Carrot", Type: "Vegetable" >, < Name: "Carrot", Type: "Vegetable" >, < Name: "Carrot", Type: "Vegetable" >, < Name: "Apple", Type: "Fruit" >, < Name: "Apple", Type: "Fruit" >, < Name: "Carrot", Type: "Vegetable" >]; const resultArray = []; arrayOfObjects.map(item => < //for each item in arrayOfObjects check if the object exists in the resulting array if(resultArray.find(object => < if(object.Name === item.Name && object.Type === item.Type) < //if the object exists iterate times object.times++; return true; //if it does not return false >else < return false; >>)) < >else < //if the object does not exists push it to the resulting array and set the times count to 1 item.times = 1; resultArray.push(item); >>) console.log(resultArray)
It’s better to use .reduce instead of .map as the latter is primarily used to apply a certain function on each element of an array and get an array of function execution results.
Array .reduce() method, on the other hand, is executing a function (callback) on each item too but it’s passing the result from one element array to another. So we can use an empty array as a start and fill it with an object or iterate .times property in case the current element is existing in the accumulating array passed to each callback.
let arrayOfObjects = [ < Name: "Apple", Type: "Fruit" >, < Name: "Carrot", Type: "Vegetable" >, < Name: "Carrot", Type: "Vegetable" >, < Name: "Carrot", Type: "Vegetable" >, < Name: "Apple", Type: "Fruit" >, < Name: "Apple", Type: "Fruit" >, < Name: "Carrot", Type: "Vegetable" >]; const newArrayOfObjects = arrayOfObjects.reduce((accumulator, object) => < if(objectFound = accumulator.find(arrItem =>arrItem.Name === object.Name && arrItem.Type === object.Type)) < objectFound.times++; >else < object.times = 1; accumulator.push(object); >return accumulator; >, []); console.log(newArrayOfObjects);
I think you’d be best suited by creating a helper object. A helper object will initially be empty, but will become populated slowly by what you’re reading through. I’m going to assume that the keys in your array are consistent.
const keys = ["Name","Type"] var counterObj = <> let keyForCounterObj arrayOfObjects.forEach((obj)=>< keyForCounterObj = '' keys.forEach((key)=> < keyForCounterObj += String(objJavascript duplicate object in array) >if(counterObjJavascript duplicate object in array)< counterObjJavascript duplicate object in array.times ++ >else< counterObjJavascript duplicate object in array = < . obj, times:1 >>>
Let’s break that down, because I understand that it might be a little bit confusing if you’ve never seen this setup before.
We’re looping through each object in the array, and we’re constructing a key based on all of the values that this object is storing. For example, arrayOfObjects[0] will create a key of «AppleFruit.» (I’m using the String() method just in case this is being applied to an object with only integer or floating point values, as those are invalid to create a key in javaScript. It isn’t necessary for your specific question)
Once we have that key, we check to see if it exists in our counterObject. If it does not exist, then we define it. We set the «times» attribute to 1, because we just created this object; it wouldn’t exist unless we had just found it.
If the object does already exist, then we just increment the «times» attribute. At the end, we have an object that looks like this:
counterObj = < AppleFruit: < Name:"Apple", Type:"Fruit", times:3, >, CarrotVegetable: < Name:"Carrot", Type:"Vegetable", times:4, >>
Okay, so now we have an object of objects. Let’s turn that into an array!
let newArrayOfObjects = [] const counterObjKeys = Object.keys(counterObj) counterObjKeys.forEach((key)=>
This will return the final value in the format that you specified!
Find duplicate values in objects with Javascript
I want to get the objects that have duplicate values in them and based on what values to search for. I.e , I want to get the object that has a duplicate value «name» and «age» but nog «country» so I will end up with:
array.forEach(function(name, age) < if(array.name == name || array.age == age)< console.log(the result) >>)
5 Answers 5
You can use 2 reduce . The first one is to group the array. The second one is to include only the group with more than 1 elements.
var array = [,,,,,] var result = Object.values(array.reduce((c, v) => < let k = v.name + '-' + v.Age; c[k] = c[k] || []; c[k].push(v); return c; >, <>)).reduce((c, v) => v.length > 1 ? c.concat(v) : c, []); console.log(result);
I’m a little late to the party but this might help someone who’s facing the same problem, as it is, I believe, an easier to understand solution:
const duplicates = []; array.forEach((el, i) => < array.forEach((element, index) => < if (i === index) return null; if (element.name === el.name && element.Age === el.Age) < if (!duplicates.includes(el)) duplicates.push(el); >>); >); console.log("duplicates", duplicates);
Two things might be tricky to understand:
- with forEach you can provide a second argument that will be an index. This is to make sure we don’t compare the same two array entries with each other (if (i === index) return null; -> to abort the forEach)
- !duplicates.includes («if not duplicates includes) checks before adding an element to the duplicates array if it’s already there. Since <> === <> is false in JS, this will not be a problem with «equal» objects already in the duplicates array, but will simply avoid adding the same element twice in one forEach loop
Edit: An even nicer solution would be this:
const duplicates = array .map((el, i) => < return array.find((element, index) => < if (i !== index && element.name === el.name && element.Age === el.Age) < return el >>) >) .filter(Boolean) console.log("duplicates:", duplicates)
It has no side effects and all logic is in one if statement. The filter is needed to sort out undefined instances.
Collect unique objects in JavaScript array
But not sure how I can filter out duplicates. Any suggestion? Edit: My object on two different array are not same. At least based on number of properties.
4 Answers 4
To Remove Duplicates With All Identical Properties
This was the original question.
The Set object lets you store unique values of any type, whether primitive values or object references.
You can also use object literals.
var list = [JSON.stringify(), JSON.stringify()]; var unique_list = new Set(list); // returns Set "> var list = Array.from(unique_list); // converts back to an array, and you can unstringify the results accordingly.
For more ways to construct a set back to an array, you can follow instructions here. If you can’t use ES6 (which is what defines Set ), there’s a polyfill for older browsers.
To Remove Objects with Duplicate Subset of Properties
Unfortunately, these objects are no longer strictly duplicates and cannot be tackled in a friendly way using Set , for instance.
The easiest way to approach this type of problem is to iterate through the array of objects, identify those with repeated property values, and eliminate in place using splice , for example.
Updated my answer to point out this only works in ES6. A lot of browsers have pretty much introduced support for ES6. There’s a polyfill for Set .
If you use firstDataSet.concat(secondDataSet) this will create a new array without unsetting the original arrays, so you may also want firstDataSet = secondDataSet = null
Sorry all for not being clear on first place. My object on second array have some extra properties that’s why I can’t use Set.
@αƞjiβ If they have extra properties, they’re not — strictly speaking — duplicates. The best you can do is iterate through the new array, find those with matching properties, and eliminate.
This can be achieved By extending Set class Like below
var firstDataSet = [ , , , ]; var secondDataSet = [ , , , ]; Array.prototype.unshift.apply(firstDataSet , secondDataSet ); //console.log(firstDataSet) class UniqueSet extends Set < constructor(values) < super(values); const data = []; for (let value of this) < if (data.includes(JSON.parse(value.id))) < this.delete(value); >else < data.push(value.id); >> > > console.log(new UniqueSet(firstDataSet))
We’ll combine the two arrays using concat , then filter the resulting array using filter . For each element, we’ll find the index of the first element with the same id and name, using findIndex . If that index is the same as the current index, it means this is the first occurrence of that id and name, so we just let it pass through. Otherwise, we’ll add in new fields to the first occurrence, and filter it out.
function combine(a1, a2) < function match(e1, e2) < return e1.id === e2.id && e1.name === e2.name); >return a1.concat(a2) . filter((e1, i, a) => < let firstIndex = a.findIndex(e2 =>match(e1, e2)); if (i === firstIndex) return true; // this is the first occurrence a[firstIndex].xProp = e2.xProp; // copy over property return false; // filter out >); >
If you want to handle arbitrary properties, instead of just xProp , then change the relevant line to something like
a[firstIndex] = Object.assign(e2, a[firstIndex]);
That will replace the first occurrence with the result of copying all its properties on top of the current occurrence including whatever additional properties it may have.
Mandatory disclaimer: As always, depending on your environment, you may not have arrow functions, or Array#findIndex , or Object.assign . In such cases, rewrite/polyfill/transpile as necessary.