Reputation: 5241
as I describe my problem in title, I need implement following algorithm:
I got some array of elements, e.g.:
let arr1 = [
{id:1, foo1: '...', foo2: '...'},
{id:2, foo1: '...', foo2: '...'},
{id:3, foo1: '...', foo2: '...'},
];
in somewhere in my application I got another array arr2 which can contains elements which already are in arr1.
let arr2 = [
{id:1, foo1: '...', foo2: '...'},
{id:4, foo1: '...', foo2: '...'},
{id:5, foo1: '...', foo2: '...'},
];
In case arr1 contains each element of arr2 I need exclude these elements from arr1. And in second case where arr2 contains least one element which is also not in arr1, all elements of arr2 will append to arr1.
I tried lodash's function _.xorBy(arr1, arr2, 'id')
which doesn't work in all cases. I looked for in lodash's docs some another function for my needs but I didn't found anything.
Here is my expected behavior (I use just number but in real app there objects with this ids):
Can you help me solve my problem, or show my some elegant way to do that? Thanks in advice.
Upvotes: 0
Views: 807
Reputation: 191976
If the _.difference()
array length between arr2
and arr1
is greater than 0
, return a _.union()
of the arrays. If not return the _.difference()
between arr1
and arr2
.
Note 1: _.difference(arr2, arr1)
is not equal to _.difference(arr1, arr2)
because the order and references of result values are determined by the first array.
Note 2: The example uses arrays of primitives. For arrays of objects use the By
versions - _.differenceBy()
and _.unionBy()
with the property iteratee shorthand - _.differenceBy(arr1, arr2, 'id')
.
const incEx = (arr1, arr2) =>
_.difference(arr2, arr1).length > 0 ?
_.union(arr1, arr2)
:
_.difference(arr1, arr2);
console.log(incEx([1,2,3,4,5], [1,2,3]));
console.log(incEx([1,2,3,4,5], [1,2,6]));
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.5/lodash.min.js"></script>
Upvotes: 3
Reputation: 386604
A plain Javascript solution with Set
.
function merge(array1, array2) {
var ids1 = new Set(array1.map(({ id }) => id)),
ids2 = new Set(array2.map(({ id }) => id));
return array2.every(({ id }) => ids1.has(id))
? array1.filter(({ id }) => !ids2.has(id))
: array1.concat(array2.filter(({ id }) => !ids1.has(id)));
}
var array1 = [{ id: 1 }, { id: 2 }, { id: 3 }],
array2 = [{ id: 1 }, { id: 4 }, { id: 5 }];
console.log(merge(array1, array2));
.as-console-wrapper { max-height: 100% !important; top: 0; }
Upvotes: 1
Reputation: 68393
In case arr1 contains each element of arr2 I need exclude these elements from arr1.
To check if all arr2
is contained in arr1
var hasAllValues = arr2.every( s => !!arr1.find( t => t.id == s.id ) )
hasAllValues
is true if all arr2
is in contained in arr1
Use filter
to remove those values in arr1
,
arr1 = arr1.filter( s => arr2.find( t => t.id == s.id ) );
And in second case where arr2 contains least one element which is also not in arr1, all elements of arr2 will append to arr1.
find the values of arr2 which are not arr1 using
var arr3 = arr2.filter( s => !!arr1.find( t => t.id == s.id ) );
arr1 = arr1.concat( arr3 );
So, final solution would be
var hasAllValues = arr2.every( s => !!arr1.find( t => t.id == s.id ) )
if ( hasAllValues )
{
arr1 = arr1.filter( s => !arr2.find( t => t.id == s.id ) );
}
else
{
var arr3 = arr2.filter( s => !arr1.find( t => t.id == s.id ) );
arr1 = arr1.concat( arr3 );
}
Demo of scenario 1
let arr1 = [{
id: 1
},
{
id: 2
},
{
id: 3
},
{
id: 4
}
];
let arr2 = [{
id: 1
},
{
id: 4
}
];
var hasAllValues = arr2.every(s => !!arr1.find(t => t.id == s.id))
if (hasAllValues) {
arr1 = arr1.filter(s => !arr2.find(t => t.id == s.id));
} else {
var arr3 = arr2.filter(s => !arr1.find(t => t.id == s.id));
//console.log(arr3)
arr1 = arr1.concat(arr3);
}
console.log(arr1);
Demo of scenario 2
let arr1 = [{
id: 1
},
{
id: 2
},
{
id: 3
}
];
let arr2 = [{
id: 1
},
{
id: 4
},
{
id: 5
}
];
var hasAllValues = arr2.every(s => !!arr1.find(t => t.id == s.id))
if (hasAllValues) {
arr1 = arr1.filter(s => !arr2.find(t => t.id == s.id));
} else {
var arr3 = arr2.filter(s => !arr1.find(t => t.id == s.id));
//console.log(arr3)
arr1 = arr1.concat(arr3);
}
console.log(arr1);
Upvotes: 0