Array method 系列之七 —— intersection
intersection和difference是功能相反的兩個方法。
difference是拋出數(shù)組中相同的部分,留下不同的部分,即取補集。
而intersection是留下相同的部分,即取交集。
intersection系列包含三個方法:intersection、intersectionBy、intersectionWith。
和difference系列相似,intersection提供多個數(shù)組的基礎比較取交集。
intersectionBy利用iteratee方法對數(shù)組元素進行預先處理。
intersectionWith利用comparator比較器自定義比較方法。
但是三種方法的思路很相似。
- 對參數(shù)進行預處理。得到
array,comparator,iteratee。 - 執(zhí)行
baseIntersection方法- 根據(jù)數(shù)組長度判斷是否緩存。緩存源碼此處略過。
- 雙重遍歷:判斷第一個數(shù)組的每個元素是否包含在其余數(shù)組中。
- 結(jié)果返回。
以下是源碼。
// intersection.js
// 注意此處傳參是...arrays
function intersection(...arrays) {
// 參數(shù)處理
const mapped = map(arrays, castArrayLikeObject)
// 執(zhí)行核心方法
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()
}
// 以上為參數(shù)處理,分離得到數(shù)組和迭代器
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()
}
// 以上為參數(shù)處理,分離得到數(shù)組和比較器
return (mapped.length && mapped[0] === arrays[0])
? baseIntersection(mapped, undefined, comparator)
: []
}
duangduangduang,核心算法出爐。
// baseIntersection
function baseIntersection(arrays, iteratee, comparator) {
// includes方法,判斷數(shù)組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進行查詢的數(shù)組集合
while (othIndex--) {
// array為數(shù)組中的每個元素,即每個需要查詢的數(shù)組
array = arrays[othIndex]
if (othIndex && iteratee) {
array = map(array, (value) => iteratee(value))
}
maxLength = Math.min(array.length, maxLength)
// 設置緩存集合,緩存集合caches的每個元素標識與之相對應的數(shù)組元素是否需要緩存
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數(shù)組中的每個元素,賦值為value
let value = array[index]
const computed = iteratee ? iteratee(value) : value
value = (comparator || value !== 0) ? value : 0
// 判斷條件:若結(jié)果數(shù)組result中不包含當前元素value,繼續(xù)執(zhí)行算法。
if (!(seen
? cacheHas(seen, computed)
: includes(result, computed, comparator)
)) {
othIndex = othLength
while (--othIndex) {
const cache = caches[othIndex]
// 內(nèi)層遍歷:遍歷arrays數(shù)組集合除了第一項的所有數(shù)組,如果該數(shù)組包含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
}