Reputation:
so I have an array containing some objects. I want to compare these objects with each other. If the fromId
AND the toId
properties are the same, it is an duplicate.
Example:
const data = [{
fromId: 1,
toId: 2,
finished: true
}, {
fromId: 1,
toId: 2,
finished: false
}, {
fromId: 5,
toId: 9,
finished: false
}, {
fromId: 1,
toId: 5,
finished: true
}, {
fromId: 2,
toId: 1,
finished: false
}];
$(document).ready(() => {
const duplicates = data.filter(x =>
data
.filter(y => y.fromId == x.fromId && y.toId == x.toId)
.length > 1
);
console.log(duplicates);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
And I want to get the length of this data array but only with unique values. I tried to remove all duplicate values and found a solution here
Get all non-unique values (i.e.: duplicate/more than one occurrence) in an array
const data = [1, 2, 3, 4, 5, 2, 2, 6, 7, 8, 2, 9, 2, 2, 2, 2, 2];
$(document).ready(() => {
const uniqueValues = data.filter((connection, index) => data.indexOf(connection) == index);
console.log(uniqueValues);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
but on this solution I just use indexOf
for the whole object. How can I compare the fromId
and toId
and remove the duplicate on same matches?
From the original array I would remove one
{
fromId: 1,
toId: 2,
finished: false
}
because the fromId
and toId
exist already at another object.
Upvotes: 3
Views: 1428
Reputation: 178160
Have a go with a simple forEach - this is plain JS and not ES5/6 or jQuery
const data = [{fromId: 1,toId: 2,finished: true},{fromId: 1,toId: 2,finished: false}, {fromId: 5,toId: 9,finished: false}, {fromId: 1,toId: 5,finished: true}, {fromId: 2, toId: 1, finished: false }];
var combos = [];
var dupes = [];
var unique = [];
data.forEach(function(item){
var combo = ""+item.fromId+"."+item.toId;
if (combos.indexOf(combo) == -1) {
combos.push(combo);
unique.push(item);
}
else {
dupes.push(item);
}
});
console.log("dupes",dupes);
console.log("unique",unique,unique.length);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
Upvotes: 0
Reputation: 1787
Yeah, many options available... Will give you another one with lodash/fp
:
Assuming you have:
import {flow, map, uniq} from 'lodash/fp'
Do this:
const count = flow(
map(o => o.fromId + '.' + o.toId),
uniq,
)(data).length
console.log('Count: ', count)
Upvotes: 0
Reputation: 2089
While CertainPerformance's answer is probably better for your scenario, the indexOf
alternative that does not compare item identities would be findIndex
. However, this is ES6+ only, but most modern browsers implement it (sorry, no IE11).
Source: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/findIndex
Upvotes: 0
Reputation: 1876
You can create a new array, and push the lements only once, checking if they already exists or not using inArray function from jQuery:
const data = [{
fromId: 1,
toId: 2,
finished: true
}, {
fromId: 1,
toId: 2,
finished: false
}, {
fromId: 5,
toId: 9,
finished: false
}, {
fromId: 1,
toId: 5,
finished: true
}, {
fromId: 2,
toId: 1,
finished: false
}];
$(document).ready(() => {
var filtered = [];
$.each(data, function(i, item){
if($.inArray(item, filtered) === -1){
filtered.push(item);
}
});
console.log(filtered.length);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
jQuery inArray()
Upvotes: 0
Reputation: 30739
You can use Array.reduce()
to filter the array with unique objects and then get the length value together with the unique array:
const data = [{
fromId: 1,
toId: 2,
finished: true
}, {
fromId: 1,
toId: 2,
finished: false
}, {
fromId: 5,
toId: 9,
finished: false
}, {
fromId: 1,
toId: 5,
finished: true
}, {
fromId: 2,
toId: 1,
finished: false
}];
$(document).ready(() => {
var uniqueArray = data.reduce((acc, obj)=>{
var existObj = acc.find(item => item.fromId === obj.fromId && item.toId === obj.toId);
if(existObj){
return acc;
}
acc.push(obj);
return acc;
},[]);
console.log('unique array ', uniqueArray);
console.log('length of unique object ', uniqueArray.length);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
Upvotes: 1
Reputation: 370929
Rather than filter
nested in another filter
(bad runtime complexity), since you're just looking for the length of the resulting unique array, you might instead combine each fromId
and toId
into a string, put that string into a Set
(which only retains unique values), and then check that Set
's size:
const data=[{fromId:1,toId:2,finished:!0},{fromId:1,toId:2,finished:!1},{fromId:5,toId:9,finished:!1},{fromId:1,toId:5,finished:!0},{fromId:2,toId:1,finished:!1}];
const idSet = new Set(data.map(({ fromId, toId }) => fromId + '_' + toId));
console.log(idSet.size);
Upvotes: 1