lodash-9 sortedIndex, sortedIndexBy, sortedIndexOf, sortedLastIndex
前言
今天是 lodash 的第 9 篇,今天是周五啦,今天带来的是 sortedIndex, sortedIndexBy, sortedIndexOf, sortedLastIndex
看似很多,其实用的也就是一个底层基础方法 - baseSortedIndex
Api
_.sortedIndex([30, 50], 40)
Uses a binary search to determine the lowest index at which value should be inserted into array in order to maintain its sort order.
使用二分法确定
value在被插入 有序数组 的最小下标
Arguments
- array(Array) : The sorted array to inspect.
- value()* : The value to evaluate.
Returns
(number) : Returns the index at which value should be inserted into array.
Example
_.sortedIndex([30, 50], 40);
// => 1
source
function sortedIndex(array, value) {
  return baseSortedIndex(array, value);
}
使用 baseSortedIndex 确定位置
baseSortedIndex
只有数组是 有序 的,才可以使用
二分法
function baseSortedIndex(array,value){
  var low = 0,
      high = array == null ? low : array.length;
      if (typeof value == 'number') {
        while (low < high) {
          var mid = (low + high) >>> 1,
              computed = array[mid];
    
          if (computed < value) {
            low = mid + 1;
          } else {
            high = mid;
          }
        }
        return high;
      }
}
使用 二分法 高效的确定位置,因为 low < high,所以可以使用 high = mid,取不到 mid
可能 对于 >>> 有些陌生
>>> 是 位运算 的一种,名字叫 「无符号右移」, 简单来说,就是 二进制往右移动几位
比如 5 >>> 1 就是 数字 5 转化为 二进制,然后向右移动 1 位,相当于 / 2
0101 向右移动一位 010 , 转为 10 进制是 2
console.log( (2 + 3) >>> 1) // 2
console.log( (3 + 3) >>> 1) // 3
_.sortedIndexBy(array, value, [iteratee=_.identity])
This method is like _.sortedIndex except that it accepts iteratee which is invoked for value and each element of array to compute their sort ranking. The iteratee is invoked with one argument:  (value) .
Arguments
- array(Array) : The sorted array to inspect.
- value()* : The value to evaluate.
- [iteratee=_.identity](Function) : The iteratee invoked per element.
Returns
(number) : Returns the index at which value should be inserted into array.
Example
var objects = [{ 'x': 4 }, { 'x': 5 }];
 
_.sortedIndexBy(objects, { 'x': 4 }, function(o) { return o.x; });
// => 0
 
// The `_.property` iteratee shorthand.
_.sortedIndexBy(objects, { 'x': 4 }, 'x');
// => 0
通过最后的 条件, 找到应该被插入的位置
source
function sortedIndexBy(array, value, iteratee) {
  return baseSortedIndexBy(array, value, baseIteratee(iteratee));
}
baseIteratee 简易版
function baseIteratee(iteratee){
    if(typeof iteratee == "function"){
        return iteratee
    }
    
    if(typeof iteratee == "string"){
        return (object)=>{
            return object[iteratee]
        }
    }
}
baseSortedIndexBy
依然用的是
二分法,只不过加上了iteratee方法处理数据
function baseSortedIndexBy(array, value, iteratee){
  var low = 0,
      high = array == null ? 0 : array.length;
       
      // 对传入的 value 做处理
      value = iteratee(value);
      while (low < high) {
        let mid = (low + high) >>>1;
        // 对 array[mid] 做同样的处理
        let computed = iteratee(array[mid]);
        if( computed < value){
          low = mid + 1
        }else {
          high = mid
        }
      }
      return high
}
以下图为例
var objects = [{ 'x': 4 }, { 'x': 5 }];
 
_.sortedIndexBy(objects, { 'x': 4 }, function(o) { return o.x; });
// value 执行 获得 4
// array[mid] 执行 获得 4,5
//  相互比较
使用 iteratee 把 x 的值 提取出来,也要把 iteratee(array[mid]) 提取出来,然后做比较
sortedIndexOf(array, value)
This method is like _.indexOf except that it performs a binary search on a sorted array.
Arguments
- array(Array) : The array to inspect.
- value()* : The value to search for.
Returns
(number) : Returns the index of the matched value, else -1.
_.sortedIndexOf([4, 5, 5, 5, 6], 5);
// => 1
_.sortedIndexOf([4, 5, 5, 5, 6], 3);
// => -1
这个 和上文的 sortedIndex 有些相似,但是 sortedIndex 是找到合适的插入位置,
sortedIndexOf 是在 「已排序」的数组中找到 下标(indexOf)
function sortedIndexOf(array, value) {
    var index = baseSortedIndex(array, value);
    
     if (index < arr.length && array[index] == value) {
          return index;
     }
     
     return -1;
}
原理就是通过 baseSortedIndex 找到 下标,然后判断找到的下标对应的 值 是否与传入的 value 相等
_.sortedLastIndex(array, value)
_.sortedLastIndex([4, 5, 5, 5, 6], 5);
// => 4
和 sortedIndexOf 的区别在于 sortedLastIndex 是找到最后一个相等的位置
需要对 二分法 做一点处理
source
function sortedLastIndex(array, value) {
  return baseSortedIndex(array, value, true);
}
function baseSortedIndex(array, value, retHighest) {
  var low = 0,
      high = array == null ? low : array.length;
  if (typeof value == 'number') {
    while (low < high) {
    
      var mid = (low + high) >>> 1,
          computed = array[mid];
         // 🚀🚀🚀 区别主要在这个地方
      if ( retHighest ? (computed <= value) : (computed < value) ) {
        low = mid + 1;
      } else {
        high = mid;
      }
    }
    return high;
  }
}
如果 computed 和 value 是相同的,low 继续往前走,直到 computed > value 为止,此时就是最右侧
结尾
今天主要是利用 二分法 对 已排序 的数组进行操作
转载自:https://juejin.cn/post/7250291603813941306




