lodash源码分析每日一练 - 数组 - difference/differenceBy/differenceWith

本文介绍了JavaScript中的三种数组去重方法:_.difference,.differenceBy,.differenceWith,分别通过不同的参数实现基本去重、带迭代器比较和自定义比较。核心是baseDifference和相关辅助函数。
摘要由CSDN通过智能技术生成

今日分享:

每一步都是曼妙的风景~

_.difference(array, [values])

使用:
创建一个具有唯一array值的数组,每个值不包含在其他给定的数组中。(注:即创建一个新数组,这个数组中的值,为第一个数字(array 参数)排除了给定数组中的值。)该方法使用SameValueZero做相等比较。结果值的顺序是由第一个数组中的顺序确定。
使用示例:

.difference([3, 2, 1], [4, 2]);
// => [3, 1]

尝试手写:

①返回新数组;②查重;③只查第一个数组相对别的数据是否有重复,不会合并之后再去重。

	let dif_arr1 = [3,2,1],dif_arr2 = [4,2];
	function my_difference(arr1, arr2) {
        let newArr = [];
        for(var i = 0 ; i < arr1.length; i++) {
            if(arr2.indexOf(arr1[i]) === -1) {
                newArr.push(arr1[i])
            }
        }
        return newArr;
    }
    console.log(my_difference(dif_arr1,dif_arr2)); // [3, 1]

源码方案:

var difference = baseRest(function(array, values) {
  return isArrayLikeObject(array)
    ? baseDifference(array, baseFlatten(values, 1, isArrayLikeObject, true))
    : [];
});

// 补充函数解释 ①baseRest
function baseRest(func, start) {
  return setToString(overRest(func, start, identity), func + '');
}
// 补充函数解释 ②isArrayLikeObject
function isArrayLikeObject(value) {
  return isObjectLike(value) && isArrayLike(value);
}
/** 
* baseFlatten函数:将数组扁平化
**/
// ③ baseDifference  核心源码
function baseDifference(array, values, iteratee, comparator) {
  var index = -1,
      includes = arrayIncludes,
      isCommon = true, 
      length = array.length,
      result = [],
      valuesLength = values.length;
	// 判断非空
  if (!length) {
    return result;
  }
  // 每个元素都被调用的迭代对象,支持对目标元素进行迭代执行
  if (iteratee) {
    values = arrayMap(values, baseUnary(iteratee));
  }
  // 为每个元素调用的比较器, 支持比较关系不限于等于; 存在比较器,isCommon修改为false,否则为true默认进行查重
  if (comparator) {
    includes = arrayIncludesWith;
    isCommon = false;
  }
  // 数目较大时使用set查找
  else if (values.length >= LARGE_ARRAY_SIZE) {
    includes = cacheHas;
    isCommon = false;
    values = new SetCache(values);
  }
  // 这个地方 outer 的用法不太懂,打个※。后面继续学习后补充
  outer:
  while (++index < length) {
    var value = array[index],
    // 存在迭代器,对目标元素进行迭代后返回,否则赋值value
        computed = iteratee == null ? value : iteratee(value);

    value = (comparator || value !== 0) ? value : 0;
    // 根据传入的比较器进行比较
    	// 常规查重。computed === computed 只有值为NaN的情况为false
    if (isCommon && computed === computed) {
      var valuesIndex = valuesLength;
      while (valuesIndex--) {
        if (values[valuesIndex] === computed) {
          continue outer;
        }
      }
      result.push(value);
    }
    // 根据比较器进行查重 includes 为之前赋值的比较器
    else if (!includes(values, computed, comparator)) {
      result.push(value);
    }
  }
  return result;
}

类似方法

.differenceBy(array, [values], [iteratee=.identity])

它接受一个 iteratee (注:迭代器), 调用array 和 values 中的每个元素以产生比较的标准。 结果值是从第一数组中选择。iteratee 会调用一个参数:(value)。(注:首先使用迭代器分别迭代array 和 values中的每个元素,返回的值作为比较值)。
使用示例:

_.differenceBy([3.1, 2.2, 1.3], [4.4, 2.5], Math.floor);
// => [3.1, 1.3]
 
// The `_.property` iteratee shorthand.
_.differenceBy([{ 'x': 2 }, { 'x': 1 }], [{ 'x': 1 }], 'x');
// => [{ 'x': 2 }]

源码

var differenceBy = baseRest(function(array, values) {
  var iteratee = last(values);
  if (isArrayLikeObject(iteratee)) {
    iteratee = undefined;
  }
  return isArrayLikeObject(array)
    ? baseDifference(array, baseFlatten(values, 1, isArrayLikeObject, true), baseIteratee(iteratee, 2))
    : [];
});
_.differenceWith(array, [values], [comparator])

它接受一个 comparator (注:比较器),它调用比较array,values中的元素。 结果值是从第一数组中选择。comparator 调用参数有两个:(arrVal, othVal)。
使用示例:

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

源码:

var differenceWith = baseRest(function(array, values) {
  var comparator = last(values);
  if (isArrayLikeObject(comparator)) {
    comparator = undefined;
  }
  return isArrayLikeObject(array)
    ? baseDifference(array, baseFlatten(values, 1, isArrayLikeObject, true), undefined, comparator)
    : [];
});

对比

可以看到,三个方法调用的核心方法是一致的,通过传参不同返回不同结果。核心源码支持查重、计算后查重、自定义比较条件。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值