sarah
sarah

Reputation: 247

Comparing arrays in javascript where order doesn't matter

I am learning Javascript, and I saw a function on SO for comparing arrays to check if they are same. However, my current function returns false if the two arrays are [string1,string2] & [string2,string1]. Basically, the two positions are interchanged. The code is as follows:

function _compareArrays(arr1,arr2){
    var result = arr1 != null && arr2 != null && arr1.length == arr2.length && arr1.every(function(element) {
            return arr2.indexOf(element);
        });
    return result ;
}

However, I want these two arrays to be returned as same. So, I changed .every to .indexOf() and it seemed to work. But, I have a doubt, how exactly is the counter getting incremented here to make sure the comparison is being done for every element? I mean, like, in C++, we do,

for (int i = 0; i < 10; i++)
    if (arr1[i] == arr2[i]
      cout<<"Elements are same\n";

Here, I have an explicit i++ which increments the counter. How does it happen in the above function?

Thanks!

Upvotes: 2

Views: 4623

Answers (3)

Luke
Luke

Reputation: 306

So the fastest way would be to sort both arrays, then compare each one element by element. This requires 2n * log(n) + n time rather than n2 time.

function compareArrays(arr1, arr2){
  if(arr1.length !== arr2.length) return false;

  // implement custom sort if necessary
  arr1.sort();
  arr2.sort();

  // use normal for loop so we can return immediately if not equal
  for(let i=0; i<arr1.length; i++){
    if(arr1[i] !== arr2[i]) return false;
  }

  return true;
}

Upvotes: 1

doubleOrt
doubleOrt

Reputation: 2507

Your current has these issues:

  1. It will return true for these 2 arrays (I hope that you understand that this is not specific to these 2): [1, 2, 2], [1,1,2]. This problem is why I set indices to undefined after a match in my solution below.

  2. indexOf returns -1 for element's it cannot find, and any number >= 0 if it can find the element, -1 is truthy, so if an element cannot be found, your comparison will return true, and 0 is falsy, so if an element is located in the first index of the second array, your method will return false (which means the whole thing will become false, because of every...). So, you should add a ~ before the result of indexOf call: ~arr2.indexOf(element).

    See this MDN page on the Bitwise Not operator (~) and how it solves the indexOf problem I mentioned.

    I also recommend that you take a look at this answer of mine on truthy/falsy values and how they interact with && and ||.


So Try this out (it's mostly your example, except there is no indexOf used and I have fixed problem #2):

function _compareArrays(arr1,arr2){
  if(!(arr1 != null && arr2 != null && arr1.length == arr2.length)) {
    return false;
  }

  /* copy the arrays so that the original arrays are not affected when we set the indices to "undefined" */
  arr1 = [].concat(arr1);
  arr2 = [].concat(arr2);

  return arr1.every(function(element, index) {
    return arr2.some(function(e, i) {
      return e === element && (arr2[i] = undefined, true);
    });
  });
}
    
var x = ["str", "boo", "str"];
var y = ["boo", "str", "str"];
var z = ["abc", "def", "ghi"]    

console.log(_compareArrays(x, y));
console.log(_compareArrays(x, z));
console.log(_compareArrays(z, z));

It won't work if the array has any undefined elements, though.

Upvotes: 1

vader
vader

Reputation: 909

Convert the array into an object instead. Convert array values into keys and their respective count as their value. This is more performant as you iterate over the arrays only once.

function compare(a, b) {
  if (a.length !== b.length) {
    return false;
  }
  let set = {};
  a.forEach((i) => {
    if (set[i] !== undefined) {
      set[i]++;
    } else {
      set[i] = 1;
    }
  });
  let difference = b.every((i) => {
    if (set[i] === undefined) {
      return false;
    } else {
      set[i]--;
      if (set[i] === 0) {
        delete set[i];
      }
      return true;
    }
  });
  return Object.keys(set) == 0 && difference;
}

The first loop on the first array initialises the the set (object), the second loop on the second array subtracts the count and removes the keys when the count hits 0. If a key is not found or if the set is not empty at the end of the procedure, then the arrays are not similar.

Upvotes: 2

Related Questions