exception-io
exception-io

Reputation: 115

Comparing equality of elements in two arrays

I have an assignment where I am supposed to check two arrays (unsorted) with integers, to see if

  1. They have the same length
  2. The first element contains integers and the second has the same values squared, in any order

For example:

test([5,4,1], [1,16,25]) // would return true ..

What I've done so far is first sort the two input arrays, and then compare the length. Once we confirm the length is the same we iterate through each value to make sure they're equal. Keep in mind I haven't gotten to comparing the values to their squared counterpart yet, because my loop is not giving me expected results. Here is the code:

function test(arr1, arr2){
  // sort arrays
  const arr1Sort = arr1.sort(),
        arr2Sort = arr2.sort();

  // compare length and then compare values
  if(arr1Sort.length === arr2Sort.length) {
    for(let i = 0; i < arr1Sort.length; i++) {
      if(arr1Sort[i] === arr2Sort[i]) {
        return true;
      } else {
        return false;
      }
    }
  }
}

console.log(test([1,2,3], [1,5,4])); returns true but the array values are different?!

Upvotes: 4

Views: 729

Answers (2)

StackSlave
StackSlave

Reputation: 10627

This should work, no mater the data to compare:

function similar(needle, haystack, exact){
  if(needle === haystack){
    return true;
  }
  if(needle instanceof Date && haystack instanceof Date){
    return needle.getTime() === haystack.getTime();
  }
  if(!needle || !haystack || (typeof needle !== 'object' && typeof haystack !== 'object')){
    return needle === haystack;
  }
  if(needle === null || needle === undefined || haystack === null || haystack === undefined || needle.prototype !== haystack.prototype){
    return false;
  }
  var keys = Object.keys(needle);
  if(exact && keys.length !== Object.keys(haystack).length){
    return false;
  }
  return keys.every(function(k){
    return similar(needle[k], haystack[k]);
  });
}
console.log(similar(['a', {cool:'stuff', yes:1}, 7], ['a', {cool:'stuff', yes:1}, 7], true));
// not exact
console.log(similar(['a', {cool:'stuff', yes:1}, 7], ['a', {cool:'stuff', stuff:'more', yes:1}, 7, 'more stuff only at the end for numeric array']));

Upvotes: 1

CertainPerformance
CertainPerformance

Reputation: 370759

Inside the for, no matter whether the if or else is fulfilled, the function will immediately return true or false on the first iteration - it'll never get past index 0. To start with, return true only after the loop has concluded, and return false if arr1Sort[i] ** 2 !== arr2Sort[i] (to check if the first squared equals the second).

Also, when sorting, make sure to use a callback function to compare each item's difference, because otherwise, .sort will sort lexiographically (eg, [1, 11, 2]):

function comp(arr1, arr2){
  // sort arrays
  const sortCb = (a, b) => a - b;
  const arr1Sort = arr1.sort(sortCb),
      arr2Sort = arr2.sort(sortCb);

  // compare length and then compare values
  if(arr1Sort.length !== arr2Sort.length) {
    return false;
  }
  for(let i = 0; i < arr1Sort.length; i++) {
    if(arr1Sort[i] ** 2 !== arr2Sort[i]) {
      return false;
    }
  }
  return true;
}

console.log(comp([1,2,3], [1,5,4]));
console.log(comp([5,4,1], [1,16,25]));

You can decrease the computational complexity to O(N) instead of O(N log N) by turning arr2 into an object indexed by the squared number beforehand:

function comp(arr1, arr2){
  if (arr1.length !== arr2.length) {
    return false;
  }
  const arr2Obj = arr2.reduce((a, num) => {
    a[num] = (a[num] || 0) + 1;
    return a;
  }, {});
  for (let i = 0; i < arr1.length; i++) {
    const sq = arr1[i] ** 2;
    if (!arr2Obj[sq]) {
      return false;
    }
    arr2Obj[sq]--;
  }
  return true;
}

console.log(comp([1,2,3], [1,5,4]));
console.log(comp([5,4,1], [1,16,25]));

(if duplicates weren't permitted, this would be a lot easier with a Set instead, but they are, unfortunately)

Upvotes: 3

Related Questions