7

I have 2 arrays that they are identical at first but the user may remove (not able to add but just remove) items from the second array. I want to find items that are in the first array but not in the second one.

I can think of several ways to do this, but as these arrays can be very large, I'm curious to find out if anyone can offer a more efficient way:

$.grep( firstArray, function( n, i ){
  return $.inArray(n, secondArray) == -1;
});
void
  • 36,090
  • 8
  • 62
  • 107
Ashkan Mobayen Khiabani
  • 33,575
  • 33
  • 102
  • 171

5 Answers5

18

You could try to make use of filter and indexOf array methods as below:

var firstArray = [1,2,3,4,5,6];
var secondArray = [3,4,6];

var result = firstArray.filter(item => secondArray.indexOf(item) == -1);

console.log(result);
Christos
  • 53,228
  • 8
  • 76
  • 108
  • 1
    I don't get why people downvote correct answers. If you have no clue, simply shut up and learn. This is the correct answer. – connexo Mar 04 '18 at 10:18
  • As efficiency was explicitly mentioned by the author: Assuming sorted arrays one might want to do a binary search – Jan Wendland Mar 04 '18 at 10:29
5

Assuming the arrays have the same order, then you could filter with an index as closure.

var array1 = [1, 2, 3, 4, 5, 6, 7, 1, 2, 3],
    array2 = [2, 4, 6, 7, 2],
    missing = array1.filter((i => a => a !== array2[i] || !++i)(0));
    
console.log(missing);
Nina Scholz
  • 376,160
  • 25
  • 347
  • 392
  • 1
    This is imposing additional restrictions and also far less readable than Christos' answer. – connexo Mar 04 '18 at 10:20
  • @connexo, the mentiond answer relies on unique values, which may not be given. – Nina Scholz Mar 04 '18 at 10:23
  • @NinaScholz great answer, [Performance Comparison](https://jsfiddle.net/x4p0muac/23/) – Ashkan Mobayen Khiabani Mar 04 '18 at 10:55
  • @NinaScholz , could you please explain this part , a => a !== array2[i] || !++i)(0) ,thanks – Enthu Mar 25 '20 at 15:12
  • it is a closure over `i` and this returns a function with `a => ...` the function body filters out the values of `array2` in the given order. this requires a check and if unequal it returns `true` or `false` by incrementing the index and taking logical not of it. the advantage of it over the `includes/indexOf` solutions, this aswer respects the order, if more same values are included. – Nina Scholz Mar 25 '20 at 15:20
  • I'd like to know the significance of the `(0)` and if that is what allows you to build your closure over `i`. The only way I know to gain access to both the array element and the index is to use the first two filter parameters: `.filter((a,i) => …)`, and the `(0)` just threw me for a loop completely (pun not initially intended) – Brandon McConnell Jan 19 '21 at 14:38
  • 1
    @BrandonMcConnell, i need `i` for `array2`. if `i` would be the index of `array1`, it does not work to filter without an additional offset. – Nina Scholz Jan 19 '21 at 14:57
  • @Nina that part makes sense to me. What's really throwing me is the `0` – Brandon McConnell Jan 26 '21 at 20:38
  • @BrandonMcConnell, it is the start value for `i`. – Nina Scholz Jan 26 '21 at 20:41
  • @Nina thanks! Do you know where I can find documentation for that `(0)` after the filter's callback function? `.filter((i => …)(0))`. Thanks! – Brandon McConnell Jan 31 '21 at 17:34
  • @BrandonMcConnell, it is an [IIFE](https://stackoverflow.com/q/8228281/1447675) with a [closure](https://stackoverflow.com/q/111102/1447675) over `i`. – Nina Scholz Jan 31 '21 at 17:38
  • If you're still around... This would be great to post to the question this is marked as a duplicate of. I see a 2x-10x speed increase over using `filter` and a binary search (instead of `includes`). Probably a different algorithmic complexity... – Darryl Noakes Aug 23 '22 at 14:57
  • I still don't understand how it works, tho... :) – Darryl Noakes Aug 23 '22 at 14:57
2

Do a .filter on the array and check if the array 2 does not have the element using .includes

var a1 = [1,2,3,4,5,6];
var a2 = [1,3,5];

var absent = a1.filter(e=>!a2.includes(e));

console.log(absent);
void
  • 36,090
  • 8
  • 62
  • 107
  • Thanks. let me check the performance time of these algorithms. because actually, I know a way to do it but looking for better performance. – Ashkan Mobayen Khiabani Mar 04 '18 at 10:26
  • @AshkanMobayenKhiabani yea but according this is a small and fast enough code to make this task done. `.includes` is better than `.indexOf` performance wise if you just need to check array contains an element or not. – void Mar 04 '18 at 10:27
1
function arr_diff (a1, a2) {
var a = [], diff = [];
for (var i = 0; i < a1.length; i++) {
    a[a1[i]] = true;
}
for (var i = 0; i < a2.length; i++) {
    if (a[a2[i]]) {
        delete a[a2[i]];
    } else {
        a[a2[i]] = true;
    }
}
for (var k in a) {
    diff.push(k);
}
return diff;

}

Use this function to get difference between two sets.
A:Set 1
B:Set 2
A-B:Elements that are present in A but, not in B
Basic set theory

Prasanta Bose
  • 674
  • 5
  • 13
0

As user can delete items. So you can add those deleted items in a different array.

var deltedItems = [];
var position = 0;

function onDeleteItem(value){
   deltedItems[position] = value;
   position++;
}

Here, you can find all your deleted items in deltedItems variable. By using this logic you can eliminate search cost of your program.

Md. Nasir Uddin Bhuiyan
  • 1,598
  • 1
  • 14
  • 24