Not sure how do to this, so any help is greatly appreciated
Say I have :
const array1 = [1, 1, 2, 3, 4];
const array2 = [1, 2];
Desired
This will run reasonably well. I think its linear time instead of N*N
function diffOnlyOncePerElementInstance(a1, a2) {
const max = Math.max(a1.length, a2.length);
const map = {};
for (let i = 0; i < max; i++) {
const valueA = a1[i];
const valueB = a2[i];
if (i < a1.length) {
if (!Number.isInteger(map[valueA])) {
map[valueA] = 0;
}
map[valueA]++;
}
if (i < a2.length) {
if (!Number.isInteger(map[valueB])) {
map[valueB] = 0;
}
map[valueB]--
}
}
return Object.keys(map)
.map(key => new Array(Math.abs(map[key])).fill(key)) // regenerate remaining count
.reduce((a,b) => a.concat(b), []); // flatten
}
var array1 = [1, 1, 2, 3, 4],
array2 = [1, 2],
result = array1.slice(0);
array2.forEach(function(element) {
var index = result.indexOf(element)
if (index >= 0) {
result.splice(index, 1)
}
})
console.log(result)
Not sure the most efficiency way to do this in modern JS, and I'm pretty old-school, so here's an old-school solution:
var array1 = [1, 1, 2, 3, 4];
var array2 = [1, 2];
// Note this method is destructive
Array.prototype.removeFirstValueMatch = function(ar)
{
var indexesToRemoveAr = [];
var indexesToRemoveOb = {};
for(var i=0, j; i<ar.length; i++)
{
for(j=0; j<this.length; j++)
{
if(this[j] == ar[i] && !indexesToRemoveOb.hasOwnProperty(j) )
{
indexesToRemoveOb[j] = indexesToRemoveAr.length;
indexesToRemoveAr.push(j);
break;
}
}
}
var descending = indexesToRemoveAr.sort().reverse();
for(i=0; i<descending.length; i++)
{
this.splice(descending[i],1);
}
return this;
};
// Destructive
console.log(array1.removeFirstValueMatch(array2));//[1, 3, 4]
console.log(array1.removeFirstValueMatch(array2));//[3, 4]
// Non-Destructive
var array1 = [1, 1, 2, 3, 4];
console.log(array1.slice(0).removeFirstValueMatch(array2));//[1, 3, 4]
console.log(array1.slice(0).removeFirstValueMatch(array2));//[1, 3, 4]
If you are going to work with large arrays, this solution will perform very well. First convert array1
to a Map
to make your lookups quick. Then go through array2
and subtract from your map
to signify that the element should get removed. Then finally run through your map
and add the keys that have values bigger than 0
const array1 = [1, 1, 2, 3, 4];
const array2 = [1, 2];
const obj = array1.reduce((acc, cv) => {
if (acc.has(cv)) acc.set(cv, acc.get(cv) + 1);
else acc.set(cv, 1);
return acc;
}, new Map());
array2.forEach(i => {
if (obj.has(i)) obj.set(i, obj.get(i) - 1);
});
const res = [];
obj.forEach((v, k) => { if (v) res.push(k); });
console.log(res)
You can try the following. Loop through array1 and check if the element of array2 exists on array1 and splice it out.
const array1 = [1, 1, 2, 3, 4];
const array2 = [1, 2];
for(i=0;i<=array1.length;i++){
for(j=0;j<array2.length;j++){
if(array2[j] == array1[i]){
array1.splice(i,1);
}
}
}
console.log(array1);
IMO using array2
as object instead of array will be most performant way.
Here on first find of key we change the value in object so we do not filter that value again as desired in output.
const array1 = [1, 1, 2, 3, 4];
const array2 = Object.create(null,{
1:{writable: true,value:false},
2:{writable: true,value:false}
})
let op = array1.filter(e=> {
if(array2[e] === false){
array2[e] = true
return false
}
return true
})
console.log(op)
On Side note:- With object.create
we are creating a object without a prototype so it do not search for values in complete prototype chain.