1

I have two arrays of numbers I want get get the unique numbers that appears in both arrays. Then I want to also return the unique numbers from both arrays.

For example:

INPUT:
let arr1 = [1234,4056,3045]
let arr2 = [5678,1234,5001]

OUTPUT:
only in arr1: [4056, 3045] 
only in arr2: [5678, 5001] 
in both lists: [1234]

Here is my solution, it works but I can't think of how optimize my solution. Just using JavaScript, no tools like loadash. Any thoughts?:

const getUniqueNumbers = (arr1, arr2) => {
  let uniqueOfBoth = arr1.filter((ele) => {
    return arr2.indexOf(ele) !== -1
  })

  let uniqueOfList1 = arr1.filter((ele) => {
    return arr2.indexOf(ele) == -1
  })

  let uniqueOfList2 = arr2.filter((ele) => {
    return arr1.indexOf(ele) == -1
  })

  return `Unique numbers from both list are ${uniqueOfBoth} 
              Unique nums to List1 : ${uniqueOfList1}
              Unique nums to List2 : ${uniqueOfList2}
    `
}

let result = getUniqueNumbers([1234, 4056, 3045], [5678, 1234, 5001])
console.log(result)
Rick
  • 4,030
  • 9
  • 24
  • 35
bruce
  • 443
  • 1
  • 5
  • 17

3 Answers3

1

You could use Array#includes instead of Array#indexOf, because it returns a boolean value instead of the index.

For getting a difference, you could filter by the unique values of both arrays (this yields a smaller set, than to take the original arrays).

const getUniqueNumbers = (arr1, arr2) => {
  let uniqueOfBoth = arr1.filter(ele => arr2.includes(ele))
  let uniqueOfList1 = arr1.filter((ele) => !uniqueOfBoth.includes(ele))
  let uniqueOfList2 = arr2.filter((ele) => !uniqueOfBoth.includes(ele))

  return `Unique numbers from both list are ${uniqueOfBoth}\nUnique nums to List1 : ${uniqueOfList1}\nUnique nums to List2 : ${uniqueOfList2}`
}

let result = getUniqueNumbers([1234, 4056, 3045], [5678, 1234, 5001])
console.log(result)
Nina Scholz
  • 376,160
  • 25
  • 347
  • 392
  • 1
    There's something very beautiful about this answer: re-using the "present-in-both" list to retrieve unique items in each list. – Terry Jul 17 '18 at 20:13
  • This is a very intriquing approach, I sowed it to my class today and they loved your use of template literal. Really straightforward answer as well. – bruce Jul 21 '18 at 22:17
1

I think this approach is fine so long as it doesn't become a bottle neck. You are doing three O(n**2) operations to get your lists, so it could be nice if there was a way to reduce the complexity.

One thing you could try is to use a hash table that keeps count of how many times the numbers are seen. But you need to be a little clever because you can't just count otherwise you wouldn't know if 1 means arr1 or arr2. But since there are only 4 possibilities you only need 2 bits to represent them. So you add 1 when it's in array1 and 2 when it's in array1. That means 1 in is arr1, 2 in arr2, and 3 is in both. Creating the counts is only O(n+m) where n and m are the array lengths. (You still need to filter that, however, to get your final result)

const getUniqueNumbers =(arr1,arr2) =>{
    let counter = {}
    arr1.forEach(i => counter[i] = counter[i] ? counter[i] + 1 : 1)
    arr2.forEach(i => counter[i] = counter[i] ? counter[i] + 2 : 2)
    
    return counter
}
let counts = getUniqueNumbers([1234,4056,3045],[5678,1234,5001])
console.log(counts)

Then it's just a matter of filtering what you want with something like:

let both = Object.keys(counter).filter(key => result[key] === 3)
Mark
  • 90,562
  • 7
  • 108
  • 148
  • 1
    Never thought of using bits to represent the results, this solution is pretty darn brilliant :) – Terry Jul 17 '18 at 20:15
  • Loved your solution. Very easy to understand and I definitely like the approach of using numbers to keep track of the elements we came across already – bruce Jul 21 '18 at 22:16
0

Here's another version.

This solution assumes the arrays are of equal length. We first iterate through the arrays and store the values in 2 dictionaries. This eliminates any duplicate integers found in the same array. We then iterate over one of the dictionaries and check if the key is found in both, then delete that key from both. Finally, we get the remaining keys from both dictionaries and store them as arrays.

const fn = (arr1, arr2) => {
  const obj = {
    arr1: [],
    arr2: [],
    both: []
  };
  const dict1 = {};
  const dict2 = {};

  for (let i = arr1.length; i--;) {
    dict1[arr1[i]] = true;
    dict2[arr2[i]] = true;
  }

  for (let key in dict1) {
    if (key in dict2) {
      obj.both.push(key);
      delete dict1[key];
      delete dict2[key];
    }
  }

  obj.arr1 = Object.keys(dict1);
  obj.arr2 = Object.keys(dict2);

  return obj;
}

const arr1 = [1234, 4056, 3045];
const arr2 = [5678, 1234, 5001];

console.log(fn(arr1, arr2));
Geuis
  • 41,122
  • 56
  • 157
  • 219