Ask Question

JS - How can I check if 2 arrays contains the same values

Given I have 2 number arrays. How can I check efficiently if the values are same?
I would prefer vanilla JavaScript solution without third party library ๐Ÿ™‚

JavaScriptarrayperformance

1983 views

Authorยดs AnkiCodes image

AnkiCodes

Last edited on

3 Answers

Best answer

It seems like some of these answers missed the efficiently part.

First off, you didn't specify if [1, 2, 3] is the same as [1, 3, 2]. But let's assume they aren't the same. Generating strings using join is way slower than just checking in a loop

function hasSameValuesInSameOrder(a, b) {
  if (a.length !== b.length) return false;
  const len = a.length;
  for (let i = 0; i < len; ++i) {
    if (a[i] !== b[i]) return false;
  }
  return true;
}

It doesn't matter if the arrays are the same or different but if the are different checking one element at a time is going exit early where as joining the arrays touches every element, on top of converting numbers to strings and all of those strings into a bigger string which all adds up to being super inefficient.

According to this benchmark using join is 1000x slower than just comparing in a loop. The best case for join will be if the arrays are the same but it will still be slower.

If [1, 2, 3] is the same as [1, 3, 2] then sorting will solve it but sorting in the compare function like one of the answers would be poor design because sort modifies the arrays. You would not expect a function that's only supposed to tell you if 2 arrays contain the same values to change your arrays. So, if you want to use sort then you need to make a copy of the arrays

function hasSameValues(a, b) {
  if (a.length !== b.length) { return false; }
  // changing the original arrays would be evil so we
  // have to make copies.
  const aSorted = a.slice().sort();
  const bSorted = b.slice().sort();
  const len = aSorted.length;
  for (let i = 0; i < len; ++i) {
    if (aSorted[i] !== bSorted[i]) {
      return false;
    }
  }
  return true;
}

but the copy and the sort take time. Sort speed is O(n log n).

We could also compare using a map. We'd use the map to count each value in the first array, then subtract from those counts with the second array. If any count is missing or goes below 0 they didn't contain the same values

function hasSameValues(a, b) {
  if (a.length !== b.length) { return false; }
  const counts = new Map();
  for (const v of a) {
    const count = counts.get(v) || 0;
    counts.set(v, count + 1);
  }
  for (const v of b) {
    const count = counts.get(v);
    if (!count) {   // undefined or 0, both mean arrays are not the same
      return false;
    }
    counts.set(v, count - 1);
  }
  return true;
}

This should effectively be less than O(n) time. Comparing these 3 methods, the join method is the slowest. The map method is the fastest by far

Note: I'm also assuming since you said you wanted to compare arrays of numbers that you actually passed in "arrays of numbers", not objects that look like arrays of numbers, not typedarrays, etcโ€ฆ so checking Array.isArray is a waste of time.

๐Ÿš€
3
Authorยดs Gabriel Vincent image
Great answer! I just wanted to add something to the sorting done in the first solution: if you have an array like [6, -2, 2, 6, -7], calling .sort() on it will produce a wrong result [ -2, -7, 2, 6, 6 ] because sort() by default treats each element of the array as a string. This can easily be fixed by writing the comparison function to be used by sort(): [ -2, -7, 2, 6, 6 ].sort((a, b) => a - b )

Since OP asked for a vanilla solution, my answer is very similar to @Anki Batsukh's, only I removed type annotations, which are not vanilla JS and added a few more checks before actually comparing the arrays.

function hasSameValues(arr1, arr2) {
  if (!arr1 || !arr2) {
    return false
  }

  if (!Array.isArray(arr1) || !Array.isArray(arr2)) {
    return false
  }

  if (arr1.length !== arr2.length) {
    return false
  }

  return arr1.join('|') === arr2.join('|')
}
๐Ÿ‘
1
Authorยดs gman image
this is slow

If performance is important for you, I would recommend you to check the array length first. You could create an util function like this:

function hasSameValues(arr1: number[], arr2: number[]): boolean {
  if (arr1.length !== arr2.length) {
    return false;
  }

  return arr1.join('|') === arr2.join('|');  
}

If the values in your array does not necessarily have to have the same order then you should sort them before join()

arr1.sort().join('|') === arr2.sort().join('|');
Authorยดs gman image
your answer is not JavaScript. It's also not efficient. And, the last suggestion about sort modifies the arrays.
ย (edited)
1