53
_.uniqBy(array, [iteratee=_.identity])
_.uniqBy類似uniq方法,區別是需要傳入一個iteratee方法,用來處理每一個元素之后再比較
參數
[arrays] (...Array): 需要去重的數組
[iteratee=_.identity] (Function): 處理每一個元素的迭代器
返回值
(Array): 返回去重后的新數組
例子
_.uniqBy([2.1, 1.2, 2.3], Math.floor); // => [2.1, 1.2] // The `_.property` iteratee shorthand. _.uniqBy([{ 'x': 1 }, { 'x': 2 }, { 'x': 1 }], 'x'); // => [{ 'x': 1 }, { 'x': 2 }]
源代碼:
iteratee參數也可以直接傳遞對象的屬性key,這樣的iteratee參數會被處理成一個函數,之前看過了,省略
import baseUniq from './.internal/baseUniq.js' /** * This method is like `uniq` except that it accepts `iteratee` which is * invoked for each element in `array` to generate the criterion by which * uniqueness is computed. The order of result values is determined by the * order they occur in the array. The iteratee is invoked with one argument: * (value). * * @since 4.0.0 * @category Array * @param {Array} array The array to inspect. * @param {Function} iteratee The iteratee invoked per element. * @returns {Array} Returns the new duplicate free array. * @see uniq, uniqWith * @example * * uniqBy([2.1, 1.2, 2.3], Math.floor) * // => [2.1, 1.2] */ //類似uniq方法,區別是需要傳入一個iteratee方法,用來處理每一個元素之后再比較 function uniqBy(array, iteratee) { return (array != null && array.length) ? baseUniq(array, iteratee) : [] //如果數組不為空並且數組有長度,調用baseUniq處理,否則返回空數組 } export default uniqBy
baseUniq
import SetCache from './SetCache.js' import arrayIncludes from './arrayIncludes.js'//判斷數組是否包含給定值 import arrayIncludesWith from './arrayIncludesWith.js'//判斷數組是否包含給定值,區別是它的comparator需要作為參數傳入 import cacheHas from './cacheHas.js' import createSet from './createSet.js' import setToArray from './setToArray.js' /** Used as the size to enable large array optimizations. */ const LARGE_ARRAY_SIZE = 200 /** * The base implementation of `uniqBy`. * * @private * @param {Array} array The array to inspect. * @param {Function} [iteratee] The iteratee invoked per element. * @param {Function} [comparator] The comparator invoked per element. * @returns {Array} Returns the new duplicate free array. */ //uniqBy的基礎實現,數組去重 function baseUniq(array, iteratee, comparator) { let index = -1//循環索引 let includes = arrayIncludes//類似數組的includes方法,判斷數組是否包含給定值 let isCommon = true//有沒有自定義比較器或者有沒有開啟緩存的標記 const { length } = array//數組長度 const result = []//結果數組 let seen = result//臨時數組,用來存入不重復的數組元素值 if (comparator) {//如果傳遞了自定義比較器,incledes方法就用arrayIncludesWith isCommon = false includes = arrayIncludesWith } else if (length >= LARGE_ARRAY_SIZE) {//如果數組長度超過200,就設置緩存 const set = iteratee ? null : createSet(array)//如果沒有iteratee和comparator,就直接使用ES6的set類型去重 if (set) {//如果可以用set類型去重,直接新建set對象然后再轉換成數組后返回結果 return setToArray(set) } isCommon = false//否則開啟數組緩存 includes = cacheHas seen = new SetCache } else {//如果沒有自定義比較器,數組長度也沒有超過200 seen = iteratee ? [] : result } outer: while (++index < length) {//遍歷數組 let value = array[index]//當前元素 const computed = iteratee ? iteratee(value) : value//iteratee處理后的當前元素 value = (comparator || value !== 0) ? value : 0//如果沒有傳遞comparator,將-0變為0 if (isCommon && computed === computed) {//如果沒有傳遞自定義比較器,或者沒有開啟緩存,並且computed不是NaN let seenIndex = seen.length//seen數組的長度 while (seenIndex--) {//遍歷seen數組,如果有和當前值一樣的,就跳出本次循環直接進行下一次 if (seen[seenIndex] === computed) { continue outer } } if (iteratee) {//如果有iteratee參數,seen結尾插入當前不重復的元素 seen.push(computed) } result.push(value)//結果數組結尾插入當前不重復的元素 } else if (!includes(seen, computed, comparator)) {//如果有自定義比較器或者開啟了緩存,並且seen中沒有當前元素 if (seen !== result) {//開啟緩存的情況seen數組要插入新值 seen.push(computed) } result.push(value)//結果數組插入新值 } } return result } export default baseUniq