the second most highly rated answer here is a very lucid version of what to write, this post is just to add notes on top of it: https://stackoverflow.com/questions/1187518/how-to-get-the-difference-between-two-arrays-in-javascript

const intersectionBetweenArrays = (array1, array2) =>
array1.filter(x => array2.includes(x))const arr1 = [1, 2, 3]
const arr2 = [2, 3, 5]
const res1 = intersectionBetweenArrays(arr1, [2, 3])
const res2 = intersectionBetweenArrays(arr1, arr2)
console.log(res1) // [ 2, 3 ]
console.log(res2) // [ 2, 3 ]const differenceBetweenArrays = (array1, array2, type = 'both') => {
const diffA = array1.filter(x => !array2.includes(x))
if (type === 'left') return diffA // difference
const diffB = array2.filter(x => !array1.includes(x))
if (type === 'right') return diffB
if (type === 'both') return diffA.concat(diffB) // symmetric difference
throw new Error(
"incorrect type specified. please select either 'left', 'right', or 'both'"
)
}const arr1 = [1, 2, 3]
const arr2 = [2, 3, 5]
const res1 = differenceBetweenArrays(arr1, [2, 3])
const res2 = differenceBetweenArrays(arr1, arr2)
const res3 = differenceBetweenArrays([2, 3], arr2)
console.log(res1) // [ 1 ]
console.log(res2) // [ 1, 5 ]
console.log(res3) // [ 5 ]for example, I want 'foo' and 'bar' objects:
const first = [
{ key: 'foo', value: 1212 },
{ key: 'bar', value: 1234 },
]
const second = [
{ key: 'foo', value: 1212 },
{ key: 'bar', value: 1234 },
{ key: 'baz', value: 3434 },
]params:
const intersectionBetweenArraysNaive = (array1, array2, selector) => {
if (!selector) return array1.filter(x => array2.includes(x))
return array1.filter(x => array2.map(selector).includes(selector(x)))
}so when your data matches, it does this:
const arr1 = [
{ key: 'foo', value: 1212 }, // these are the same within arr1 and arr2
{ key: 'bar', value: 1234 }, // these are the same within arr1 and arr2
]
const arr2 = [
{ key: 'foo', value: 1212 }, // these are the same within arr1 and arr2
{ key: 'bar', value: 1234 }, // these are the same within arr1 and arr2
{ key: 'baz', value: 3434 },
]
const res1 = intersectionBetweenArraysNaive(arr1, arr2, obj => obj.key)
console.log(res1) // [ { key: 'foo', value: 1212 }, { key: 'bar', value: 1234 } ]and when you data DOESN'T match, it just takes the one from array1 due to the implementation:
const arr1 = [
{ key: 'foo', value: 1212 },
{ key: 'bar', value: 1234 },
]
const arr2 = [
{ key: 'foo', value: 1111 },
{ key: 'bar', value: 5555 },
{ key: 'baz', value: 3434 },
]
const res1 = intersectionBetweenArraysNaive(arr1, arr2, obj => obj.key)
console.log(res1) // [ { key: 'foo', value: 1212 }, { key: 'bar', value: 1234 } ]strict means we compare stringified versions of the array objects, so no selectors needed.
const intersectionBetweenArraysStrict = (array1, array2) =>
array1.filter(x => array2.map(JSON.stringify).includes(JSON.stringify(x)))this will give you only full matches:
const arr1 = [
{ key: 'foo', value: 1212 },
{ key: 'bar', value: 1234 },
]
const arr2 = [
{ key: 'foo', value: 1111 },
{ key: 'bar', value: 5555 },
{ key: 'baz', value: 3434 },
]
const res2 = intersectionBetweenArraysStrict(arr1, arr2)
console.log(res2) // []if you want them, with the assumption that the values are not going to be the same:
**then you're gonna have to work out what you want to do with the clashing values (do you make them an array? do you sum them up?)
here's a very long winded first go at doing something like this
const intersectionBetweenArraysWithResolvers = (
array1,
array2,
selector,
valueResolver
) => {
if (!selector) return array1.filter(x => array2.includes(x))
return array1.map(x => {
const array2match = array2.filter(y => selector(y) === selector(x))
if (array2match.length === 0) return false
if (array2match.length !== 1)
throw new Error('do something when there is more than 1 match')
if (array2match.length === 1) {
// compare values inside and allow user to pass a function to do something about it
const array1Object = x
const array2Object = array2match[0]
if (JSON.stringify(array1Object) === JSON.stringify(array2Object))
return true
// if selector is the same, but other stuff is different...
let combined = {}
const allKeys = [
...new Set([
...Object.keys(array1Object),
...Object.keys(array2Object),
]),
]
for (const key of allKeys) {
if (!array2Object[key]) {
// if it's unique to array1's object, use it
combined[key] = array1Object[key]
}
if (!array1Object[key]) {
combined[key] = array2Object[key]
}
// else compare the values in the keys
const array1Value = array1Object[key]
const array2Value = array2Object[key]
const bothValuesMatch =
JSON.stringify(array1Value) === JSON.stringify(array2Value)
const isOneOfTheValuesIUndefined =
!JSON.stringify(array1Value) || !JSON.stringify(array2Value)
if (bothValuesMatch) {
combined[key] = array1Object[key]
} else {
const combinedValues = [array1Value, array2Value].filter(Boolean)
if (combinedValues.length === 1) {
// one of the values is undefined
combined[key] = combinedValues[0]
}
if (combinedValues.length === 2) {
if (valueResolver) {
// if the values are different, what do we wanna do?
const userFunction = valueResolver
combined[key] = userFunction(
array1Object[key],
array2Object[key],
key
)
} else {
// default resolver turns value into array of values
let combinedArray = []
array1Object[key] && combinedArray.push(array1Object[key])
array2Object[key] && combinedArray.push(array2Object[key])
combined[key] =
combinedArray.length === 1 ? combinedArray[0] : combinedArray
}
}
}
}
return combined
}
})
}params:
const arr1 = [
{ key: 'foo', value: 1212 },
{ key: 'bar', value: 1234 },
]
const arr2 = [
{ key: 'foo', value: 1111 },
{ key: 'bar', value: 5555, hoot: 'woot woot!' },
{ key: 'baz', value: 3434 },
]
const res1 = intersectionBetweenArraysWithResolvers(arr1, arr2, obj => obj.key)
const res2 = intersectionBetweenArraysWithResolvers(
arr1,
arr2,
obj => obj.key,
(value1, value2) => value1 + value2
)
console.log(res1) // [ { key: 'foo', value: [ 1212, 1111 ] }, { key: 'bar', value: [ 1234, 5555 ], hoot: 'woot woot!' } ]
console.log(res2) // [ { key: 'foo', value: 2323 }, { key: 'bar', value: 6789, hoot: 'woot woot!' } ]from SO answer
ES6 Set, for very large arrays The code above works on all browsers. However, for large arrays of more than about 10,000 items, it becomes quite slow, because it has O(n²) complexity. On many modern browsers, we can take advantage of the ES6 Set object to speed things up. Lodash automatically uses Set when it's available. If you are not using lodash, use the following implementation, inspired by Axel Rauschmayer's blog post:
function difference(a1, a2) {
var a2Set = new Set(a2)
return a1.filter(function(x) {
return !a2Set.has(x)
})
}
function symmetricDifference(a1, a2) {
return difference(a1, a2).concat(difference(a2, a1))
}Notes The behavior for all examples may be surprising or non-obvious if you care about -0, +0, NaN or sparse arrays. (For most uses, this doesn't matter.)