lodash源码分析每日一练 - 数组 - intersection / intersectionBy / intersectionWith

今日分享:

每一步都是曼妙的风景~
lodash官网地址

_.intersection([arrays])

使用:
创建唯一值的数组,这个数组包含所有给定数组都包含的元素,使用SameValueZero进行相等性比较。(注:可以理解为给定数组的交集)

使用示例:

_.intersection([2, 1], [4, 2], [1, 2]);
// => [2]

尝试手写:

①返回数组 ②“查重” ③ 返回重合部分

    let inter_arr1 = [5, 2],inter_arr2 = [2, 1],inter_arr3 = [4, 2];
    function my_intersection (...args) {
        let n = 0,len = args[0].length, arr = [];
        while (n<len) {
            for(let i = 0; i < args.length; i++) {
                if(args[i].indexOf(args[0][n]) === -1) {
                    break;
                }
                if(i == args.length -1) {
                    arr.push(args[0][n])
                }
            }
            n++;
        }
        return arr;
    }
    console.log(my_intersection(inter_arr1, inter_arr2, inter_arr3)); // [2]

源码方案:

var intersection = baseRest(function(arrays) {
// 判断并取出array中的每一项都是键值对类型
  var mapped = arrayMap(arrays, castArrayLikeObject);
  return (mapped.length && mapped[0] === arrays[0])
    ? baseIntersection(mapped)
    : [];
});
var nativeMin = Math.min;
// 核心处理逻辑
/**
 * The base implementation of methods like `_.intersection`, without support
 * for iteratee shorthands, 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.
 */
function baseIntersection(arrays, iteratee, comparator) {
// 通过参数 comparator 确定使用哪种比较函数
  var includes = comparator ? arrayIncludesWith : arrayIncludes,  		
      length = arrays[0].length,// 取第一项length
      othLength = arrays.length,// 全部要比较的数组长度
      othIndex = othLength, // 全部要比较的数组下标
      caches = Array(othLength), // 声明一个空数组
      maxLength = Infinity, // 最大长度
      result = []; // 声明一个空数组用来存放结果
  while (othIndex--) {
    var array = arrays[othIndex];
    // 存在迭代器,先迭代再比较
    if (othIndex && iteratee) {
      array = arrayMap(array, baseUnary(iteratee));
    }
    // 取数组长度和最大长度的小值
    maxLength = nativeMin(array.length, maxLength);
    // 如果存在比较器并 需要迭代处理内容或数组内容过多,则使用setcache去处理
    caches[othIndex] = !comparator && (iteratee || (length >= 120 && array.length >= 120))
      ? new SetCache(othIndex && array)
      : undefined;
  }
  array = arrays[0];

  var index = -1,
      seen = caches[0];

  outer:
  while (++index < length && result.length < maxLength) {
    var value = array[index],
        computed = iteratee ? iteratee(value) : value;

    value = (comparator || value !== 0) ? value : 0;
    if (!(seen
          ? cacheHas(seen, computed)
          : includes(result, computed, comparator)
        )) {
      othIndex = othLength;
      while (--othIndex) {
        var cache = caches[othIndex];
        if (!(cache
              ? cacheHas(cache, computed)
              : includes(arrays[othIndex], computed, comparator))
            ) {
          continue outer;
        }
      }
      if (seen) {
        seen.push(computed);
      }
      result.push(value);
    }
  }
  return result;
}

相关方法

__.ntersectionBy([arrays], [iteratee=_.identity])

使用:
这个方法类似_.intersection,区别是它接受一个 iteratee 调用每一个arrays的每个值以产生一个值,通过产生的值进行了比较。结果值是从第一数组中选择。iteratee 会传入一个参数:(value)。
使用示例:

_.intersectionBy([2.1, 1.2], [4.3, 2.4], Math.floor);
// => [2.1]
 
// The `_.property` iteratee shorthand.
_.intersectionBy([{ 'x': 1 }], [{ 'x': 2 }, { 'x': 1 }], 'x');
// => [{ 'x': 1 }]

源码方案

var intersectionBy = baseRest(function(arrays) {
  var iteratee = last(arrays),
      mapped = arrayMap(arrays, castArrayLikeObject);

  if (iteratee === last(mapped)) {
    iteratee = undefined;
  } else {
    mapped.pop();
  }
  return (mapped.length && mapped[0] === arrays[0])
    ? baseIntersection(mapped, baseIteratee(iteratee, 2))
    : [];
});
_.intersectionWith([arrays], [comparator])

使用:
这个方法类似_.intersection,区别是它接受一个 comparator 调用比较arrays中的元素。结果值是从第一数组中选择。comparator 会传入两个参数:(arrVal, othVal)。
使用示例:

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 }]

源码方案

var intersectionWith = baseRest(function(arrays) {
  var comparator = last(arrays),
      mapped = arrayMap(arrays, castArrayLikeObject);

  comparator = typeof comparator == 'function' ? comparator : undefined;
  if (comparator) {
    mapped.pop();
  }
  return (mapped.length && mapped[0] === arrays[0])
    ? baseIntersection(mapped, undefined, comparator)
    : [];
});

思考

lodash在实践中非常方便,不用担心会出现莫名其妙的意外bug,数据格式不正确顶多结果为空。
但是稍微复杂一点的逻辑处理,就会涉及很多子方法的调用,像以上对比取重,其实只需要两个循环逻辑去一一对比就好,只是选双指针或者别的对比方式去优化处理性能的区别。有点不确定使用lodash对数据处理时是否对性能方面消耗较大。

你可能感兴趣的:(前端,javascript)