Using .filter() and .map() to solve the intersection of two sets in Javascript

Rain :

I want to learn more about the JS functions .filter() and .map() ... so I'm trying to use them to solve the following:

I've got an array with two elements - two comma separated lists of numbers:

let testArray = ["2, 3, 4, 7, 14", "1, 2, 4, 7, 18"];

I want to find the intersection of these two sets / elements, and return them as an array of numbers. (or a comma-separated string would be fine as well).

My current code produces the desired output, BUT repeated twice, i.e.

[ 2, 4, 7, 2, 4, 7 ]

and I'm not yet sure why. Any help would be appreciated:

let testArray = ["2, 3, 4, 7, 14", "1, 2, 4, 7, 18"];

function findTheIntersection(array) {
    let a = array.join();
    a = a.split(',').map(Number); //.map(String);
    return a.filter(function(x){
        return a.indexOf(x) !== a.lastIndexOf(x)
    });
}

console.log(findTheIntersection(testArray));
Nick Parsons :

Currently, .indexOf() will always refer to the first occurrence of the given element, so even when you're on the last occurrence of the given element, using indexOf() will give you the index of the first occurrence if it appeared earlier on in the array.

For example:

 0  1  2  3  4   5  6  7  8  9
[2, 3, 4, 7, 14, 1, 2, 4, 7, 18]

If you're on index 0 looking at element 2, a.indexOf(2) will give 0 and a.lastIndexOf(2) will give 6. As 0 !== 6 is true, the element 2 is kept. Now if we move up in the array we eventually reach index 6. If we're on index 6 looking at element 2, performing a.indexOf(6) will still give 0 and a.lastIndexOf(6) will still give us 6. As these are not equal you'll get true and keep 2 again as part of the result.

Instead, you want to check the actual index of the element against the last index by using the index argument passed into .filter():

let testArray = ["2, 3, 4, 7, 14", "1, 2, 4, 7, 18"];

function findTheIntersection(array) {
  let a = array.join();
  a = a.split(',').map(Number);

  return a.filter(function(x, i) {
    return i !== a.lastIndexOf(x)
  });
}

console.log(findTheIntersection(testArray));

However, do note, this code doesn't find the intersection as you need, it simply finds duplicates. Instead, you can use .reduce() and only keep items in the accumulator if they appear in the current iterated array using .filter() with .includes():

const array = ["2, 3, 4, 7, 14", "1, 2, 4, 7, 18"];
const [first, ...arrs] = array.map(v => v.split(',').map(Number));

const res = arrs.reduce((acc, arr) => {
  return acc.filter(num => arr.includes(num))
}, first);

console.log(res);

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=319333&siteId=1