0

I need some advise on a better approach here. Say i've 2 arrays to compare, array1 & array2 and i need to check if values in array 1 exists in array 2, in PHP, i can use "array_diff" function which works every-time.

Be default, what i think of is to iterate through array1, and for each values of array1, compare that again array2, two iterations, this will be (n*n) time complexity, see my code below.

How do i improve this algorithm/code. My goal is to check if a value the one array in in another array. How do i improve this code so it won't take this much time of comparing two arrays.

const array1 = ["j1", "ff2", "3hj", "4sss", "5gh", "6ss", "7aqw"];
const array2 = ["klp3", "jks32", "44sss", "3hj", "5gh", "6ss", "7aqw"];

for (let index1 of array1){
  for (let index2 of array2){
    if (index1 === index2){
      console.log("Exists.", "index 1 value: " + index1, "Index 2 value: " + index2)
    }
  } 
}

I need to improve time taken. Another time complexity that is not Quadratic.

samceena
  • 266
  • 3
  • 15
  • 1
    Hint: use a data structure to perform a fast lookup if an element exists. – Willem Van Onsem Jul 07 '19 at 15:16
  • Put `array2` into a Set object and then do a lookup in that on each item in `array1`. Or if they are regular sortable values in the array, sort `array2` which allows you to do a binary search rather than a linear search. If you also sort `array1`, you can do an even more efficient binary search since you can know something about where to start the search. – jfriend00 Jul 07 '19 at 15:20
  • https://jsperf.com/array-indexof-vs-set-has – mplungjan Jul 07 '19 at 15:32

6 Answers6

3

You could take a Set and check each item of the other array.

var array1 = ["j1", "ff2", "3hj", "4sss", "5gh", "6ss", "7aqw"],
    array2 = ["klp3", "jks32", "44sss", "3hj", "5gh", "6ss", "7aqw"],
    set1 = new Set(array1);

array2.forEach(v => {
    if (set1.has(v)) console.log(v);
});

If you like t get only the common items, you could filter the array.

var array1 = ["j1", "ff2", "3hj", "4sss", "5gh", "6ss", "7aqw"],
    array2 = ["klp3", "jks32", "44sss", "3hj", "5gh", "6ss", "7aqw"],
    common = array2.filter(Set.prototype.has, new Set(array1));

console.log(...common);
Nina Scholz
  • 376,160
  • 25
  • 347
  • 392
2

I will change it from array to Map and then search

const array1 = ["j1", "ff2", "3hj", "4sss", "5gh", "6ss", "7aqw"];
const array2 = ["klp3", "jks32", "44sss", "3hj", "5gh", "6ss", "7aqw"];

let arr1Map = new Map([...array1.map((v,i)=>[v,i])])

array2.forEach(val=> arr1Map.has(val) && console.log(val))
Code Maniac
  • 37,143
  • 5
  • 39
  • 60
0

This is quite slow

https://jsperf.com/array-indexof-vs-set-has

const array1 = ["j1", "ff2", "3hj", "4sss", "5gh", "6ss", "7aqw"];
const array2 = ["klp3", "jks32", "44sss", "3hj", "5gh", "6ss", "7aqw"];
console.log(
  array1.filter((arr1) => array2.indexOf(arr1) != -1)
);
mplungjan
  • 169,008
  • 28
  • 173
  • 236
  • 1
    it's still `O(M*N)`. the same as 2 nested loops. – skyboyer Jul 07 '19 at 15:26
  • spec explicitly says [it should be](https://tc39.es/ecma262/#sec-array.prototype.indexof#sec-array.prototype.indexof) linear traversing. so I'd not expect any additional optimization under the hood for concrete implementation. – skyboyer Jul 07 '19 at 15:31
  • Thanks @mplungjan I think it still is. It's quadratic in a way. – samceena Jul 07 '19 at 15:33
  • @mplungjan this doesn't have much difference when the data set is small, when the dataset is big then it's always slower then `Set or Map or object` – Code Maniac Jul 07 '19 at 15:34
  • Thats the idea. I'm gonna be running this on a production data in some cases, so the lower the time the better, I think using a different data structure would be better. – samceena Jul 07 '19 at 15:36
0

you can use includes and indexOf:

var array1 = ["j1", "ff2", "3hj", "4sss", "5gh", "6ss", "7aqw"],
    array2 = ["klp3", "jks32", "44sss", "3hj", "5gh", "6ss", "7aqw"];

    array1.forEach( (value,index1) => {
      if(array2.includes(value)){
         var index2 = array2.indexOf(value);
         console.log(value + " found index1:" + index1 + ", index2:" + index2);
      }
});
Nemer
  • 667
  • 1
  • 6
  • 10
  • I'm not sure if Array.prototype.includes() will traverse all the elements in the array or not before telling me if it exists, because that'll make it n*n time complexity then, i'll run it check how long it takes. Thanks. – samceena Jul 07 '19 at 15:44
0

You can use Hash table to store the first array elements and then query for the second array elements. This works in O(n) as:

  1. Setting elements in HashSet would take O(n).

  2. Querying an element in HashSet would be O(1) according to amortized analysis.

Harsh Mandalgi
  • 204
  • 2
  • 5
0

When adding every value to array1, add it also to an object/cache:

var cache = {};
...
...
for (index in array2) {
    cahce.array1_value = array1_value + '##' + array2[index] + '%%' + index;
}

Then, when you check, do:

 for (let index1 of array1){
    var s = split(cache[array[index1]], '%%');
    if (cache[array1[index1]] === s[0]){
      console.log("Exists." + index1 + '/' + s[1]);
    }
  }

This is untested, and is only to give an idea.

It should be of O(n) complexity.

It also depends on which array you fill first

But it won't work when both arrays are created simultaneously (you didn't mention how arrays are created).

It takes extra time when arrays are created, but nobody told that it should be taken into account. :) Also, this solution is good for real applications, but not perhaps for interview.

Thevs
  • 3,189
  • 2
  • 20
  • 32