Array method 系列之七 —— intersection
intersection
和difference
是功能相反的两个方法。
difference
是抛出数组中相同的部分,留下不同的部分,即取补集。
而intersection
是留下相同的部分,即取交集。
intersection
系列包含三个方法:intersection
、intersectionBy
、intersectionWith
。
和difference
系列相似,intersection
提供多个数组的基础比较取交集。
intersectionBy
利用iteratee
方法对数组元素进行预先处理。
intersectionWith
利用comparator
比较器自定义比较方法。
但是三种方法的思路很相似。
- 对参数进行预处理。得到
array
,comparator
,iteratee
。 - 执行
baseIntersection
方法- 根据数组长度判断是否缓存。缓存源码此处略过。
- 双重遍历:判断第一个数组的每个元素是否包含在其余数组中。
- 结果返回。
以下是源码。
// intersection.js
// 注意此处传参是...arrays
function intersection(...arrays) {
// 参数处理
const mapped = map(arrays, castArrayLikeObject)
// 执行核心方法
return (mapped.length && mapped[0] === arrays[0])
? baseIntersection(mapped)
: []
}
// intersectionBy.js
function intersectionBy(...arrays) {
let iteratee = last(arrays)
const mapped = map(arrays, castArrayLikeObject)
if (iteratee === last(mapped)) {
iteratee = undefined
} else {
mapped.pop()
}
// 以上为参数处理,分离得到数组和迭代器
return (mapped.length && mapped[0] === arrays[0])
? baseIntersection(mapped, iteratee)
: []
}
// intersectionWith.js
function intersectionWith(...arrays) {
let comparator = last(arrays)
const mapped = map(arrays, castArrayLikeObject)
comparator = typeof comparator == 'function' ? comparator : undefined
if (comparator) {
mapped.pop()
}
// 以上为参数处理,分离得到数组和比较器
return (mapped.length && mapped[0] === arrays[0])
? baseIntersection(mapped, undefined, comparator)
: []
}
duangduangduang,核心算法出炉。
// baseIntersection
function baseIntersection(arrays, iteratee, comparator) {
// includes方法,判断数组array中是否含有目标元素value
const includes = comparator ? arrayIncludesWith : arrayIncludes
const length = arrays[0].length
const othLength = arrays.length
const caches = new Array(othLength)
const result = []
let array
let maxLength = Infinity
let othIndex = othLength
// arrays进行查询的数组集合
while (othIndex--) {
// array为数组中的每个元素,即每个需要查询的数组
array = arrays[othIndex]
if (othIndex && iteratee) {
array = map(array, (value) => iteratee(value))
}
maxLength = Math.min(array.length, maxLength)
// 设置缓存集合,缓存集合caches的每个元素标识与之相对应的数组元素是否需要缓存
caches[othIndex] = !comparator && (iteratee || (length >= 120 && array.length >= 120))
? new SetCache(othIndex && array)
: undefined
}
// 将array中的第一个元素设置为比较标准
array = arrays[0]
let index = -1
const seen = caches[0]
outer:
while (++index < length && result.length < maxLength) {
// 外层遍历:遍历array数组中的每个元素,赋值为value
let value = array[index]
const computed = iteratee ? iteratee(value) : value
value = (comparator || value !== 0) ? value : 0
// 判断条件:若结果数组result中不包含当前元素value,继续执行算法。
if (!(seen
? cacheHas(seen, computed)
: includes(result, computed, comparator)
)) {
othIndex = othLength
while (--othIndex) {
const cache = caches[othIndex]
// 内层遍历:遍历arrays数组集合除了第一项的所有数组,如果该数组包含value元素,将元素push到result中
if (!(cache
? cacheHas(cache, computed)
: includes(arrays[othIndex], computed, comparator))
) {
continue outer
}
}
if (seen) {
seen.push(computed)
}
result.push(value)
}
}
return result
}