zl程序教程

您现在的位置是:首页 >  其它

当前栏目

_.intersectionWith([arrays], [comparator])

Arrays _. Comparator
2023-09-11 14:15:02 时间

23

_.intersectionWith([arrays], [comparator])
_.intersectionWith和_.intersection一样,取数组的交集,区别是传入自定义的比较器
参数

[arrays] (...Array): 需要取交集的数组组成的数组
[comparator] (Function): 比较器

返回值

(Array):返回交集元素组成的新数组

例子

var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }];
var others = [{ 'x': 1, 'y': 1 }, { 'x': 1, 'y': 2 }];
 
_.intersectionWith(objects, others, _.isEqual);
// => [{ 'x': 1, 'y': 2 }]

源代码:

import map from './map.js'
import baseIntersection from './.internal/baseIntersection.js'
import castArrayLikeObject from './.internal/castArrayLikeObject.js'
import last from './last.js'

/**
 * This method is like `intersection` except that it accepts `comparator`
 * which is invoked to compare elements of `arrays`. The order and references
 * of result values are determined by the first array. The comparator is
 * invoked with two arguments: (arrVal, othVal).
 *
 * @since 4.0.0
 * @category Array
 * @param {...Array} [arrays] The arrays to inspect.
 * @param {Function} [comparator] The comparator invoked per element.
 * @returns {Array} Returns the new array of intersecting values.
 * @example
 *
 * const objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }]
 * const others = [{ 'x': 1, 'y': 1 }, { 'x': 1, 'y': 2 }]
 *
 * intersectionWith(objects, others, isEqual)
 * // => [{ 'x': 1, 'y': 2 }]
 */
//和intersection一样,取数组的交集,区别是传入自定义的比较器
function intersectionWith(...arrays) {
  let comparator = last(arrays)//最后一个参数是比较器
  const mapped = map(arrays, castArrayLikeObject)//循环参数数组,将不是array-like对象的参数都转变成空数组

  comparator = typeof comparator == 'function' ? comparator : undefined//判断比较器不是函数的情况就赋值undefined
  if (comparator) {//如果传递了比较器参数,就去掉map后的参数数组的最后一个元素
    mapped.pop()
  }
  return (mapped.length && mapped[0] === arrays[0])
    ? baseIntersection(mapped, undefined, comparator)
    : []
    //如果参数数组长度不为0,且第一个参数数组是array-like对象,就调用baseIntersection处理
    //否则,返回空数组
}

export default intersectionWith

下面是baseIntersection

import SetCache from './SetCache.js'
import arrayIncludes from './arrayIncludes.js'//判断数组是否包含给定值
import arrayIncludesWith from './arrayIncludesWith.js'//类似于数组的includes方法,区别是它的comparator需要作为参数传入
import map from '../map.js'
import cacheHas from './cacheHas.js'

/**
 * The base implementation of methods like `intersection` that accepts an
 * array of arrays to inspect.
 *
 * @private
 * @param {Array} arrays The arrays to inspect.
 * @param {Function} [iteratee] The iteratee invoked per element.
 * @param {Function} [comparator] The comparator invoked per element.
 * @returns {Array} Returns the new array of shared values.
 */
//取数组交集方法intersection的基础实现
//arrays需要取交集的数组组成的数组,iteratee循环时每个元素调用的迭代器,comparator比较器
function baseIntersection(arrays, iteratee, comparator) {
  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 = arrays[othIndex]//当前数组
    if (othIndex && iteratee) {//如果传递了迭代器参数,就循环当前数组为其中每个元素执行迭代器
      array = map(array, (value) => iteratee(value))
    }
    maxLength = Math.min(array.length, maxLength)//array.length和Infinity中取一个小值,要获取到一个结果数组的最大长度后面有用
    caches[othIndex] = !comparator && (iteratee || (length >= 120 && array.length >= 120))
      ? new SetCache(othIndex && array)
      : undefined
      //缓存数组处理
      //如果没有comparator,并且有iteratee或者第一个数组和当前循环到的数组的长度大于等于120,就开启缓存
      //开启缓存的时候,caches[othIndex],caches的当前值赋值为一个SetCache对象,传递当前循环到的数组作为参数
      //不开启缓存,就存一个undefined
  }
  array = arrays[0]//第一个数组,用于取交集的次序的根据

  let index = -1//循环索引
  const seen = caches[0]//缓存的第一个数组

  outer://标签语句,循环跳出时会跳到这里
  while (++index < length && result.length < maxLength) {
    //循环第一个数组,第二个条件是结果数组的长度不能超过最大长度
    let value = array[index]//第一个数组的当前循环元素
    const computed = iteratee ? iteratee(value) : value//用迭代器处理一下第一个数组的当前元素

    value = (comparator || value !== 0) ? value : 0//处理value为0的情况,因为可能还有+0,-0之类的元素值
    if (!(seen
          ? cacheHas(seen, computed)
          : includes(result, computed, comparator)
        )) {//如果有第一个数组的缓存,就用cacheHas来判断缓存里是否有computed;如果没有缓存,就用includes判断result数组里是否有computed。如果没有找到,就执行下面操作
      othIndex = othLength//需要比较的数组长度,作为循环索引
      while (--othIndex) {//循环需要比较的数组
        const cache = caches[othIndex]//当前循环到的数组的缓存
        if (!(cache
              ? cacheHas(cache, computed)
              : includes(arrays[othIndex], computed, comparator))
            ) {//有缓存就用cacheHas判断是否有当前元素;如果没有缓存就用includes判断
          continue outer//如果有一个数组里没有当前computed,就跳过,直接循环下一个第一个数组的元素
        }
      }
      //否则说明每一个数组里都有当前computed,就push到seen里和result里
      if (seen) {
        seen.push(computed)
      }
      result.push(value)
    }
  }
  return result
}

export default baseIntersection