一天一个仿lodash函数实现-sortedIndex
拖了一周了,上周一直在忙(其实是sortedIndex没咋理解好)
sortedIndex 从有序数组中找到指定数该插入的位置,用的是二分法的方式解决。
有两个关键点:有序数组,二分法
所以实现上是这样的:
function sortedIndex(arr, value){
let head = 0;
let tail = arr.length - 1;
let mid;
while(head<tail){
mid = Math.floor((head+tail)/2);
if(arr[mid]<value){
head = mid + 1;
} else {
tail = mid;
}
}
return tail;
}
在二分法中,我有个模糊的疑问,就是为什么head要mid+1,而tail不用mid-1?
配套的几个不必多说,其实就是多了判断条件或者返回罢了,实际上这几个函数在lodash源码里是抽离出底层逻辑函数,来分开调用的。
function sortedIndexBy(arr, val, it){
const iteratee = typeof it === 'string'?a=>a[it]:it
let head = 0;
let tail = arr.length - 1;
let mid;
while(head<tail){
mid = Math.floor((head+tail)/2);
if(iteratee(arr[mid])<iteratee(val)){
head = mid + 1;
} else {
tail = mid;
}
}
return tail;
}
function sortedIndexOf(arr, val){
let head = 0;
let tail = arr.length - 1;
let mid;
while(head<tail){
mid = Math.floor((head+tail)/2);
if(arr[mid]<val){
head = mid + 1;
} else {
tail = mid;
}
}
return arr[tail]===val?tail:-1;
}
关于sortedLastIndex则是查找出最后的一个index,假设数组中间有许多相等的匹配元素,函数则需要返回最后的一个的位置,这个其实很简单,在原有的判断中加多一个=判断即可。
function sortedLastIndex(arr, val){
let head = 0;
let tail = arr.length - 1;
let mid;
while(head<tail){
mid = Math.floor((head+tail)/2);
if(arr[mid]<=val){
head = mid + 1;
} else {
tail = mid;
}
}
return tail
}
function sortedLastIndexBy(arr, val, it){
const iteratee = typeof it === 'string'?a=>a[it]:it
let head = 0;
let tail = arr.length - 1;
let mid;
while(head<tail){
mid = Math.floor((head+tail)/2);
if(iteratee(arr[mid])<=iteratee(val)){
head = mid + 1;
} else {
tail = mid;
}
}
return tail;
}
function sortedLastIndexOf(arr, val){
let head = 0;
let tail = arr.length - 1;
let mid;
while(head<tail){
mid = Math.floor((head+tail)/2);
if(arr[mid]<=val){
head = mid + 1;
} else {
tail = mid;
}
}
return arr[tail]===val?tail:-1;
}