一天一个仿lodash函数实现-xor

xor 数组类异或,其实是找出一堆数组里面,只出现一次的元素集合。
所以在最开始实现时,我的逻辑是,所有数遍历一次组合起来,并且记录每个元素出现的次数,再遍历一次全部,只把出现一次的元素丢到结果里返回。

上述想法是可以实现,但后续要实现xorBy和xorWith就有点不方便.

查看了下lodash源码,它的实现方式利用了difference方法,基本上把by和with转嫁到differenceBy和differenceWith来处理了。

实际逻辑是,两层遍历,外层遍历数组,内层算出每一个数组和其他数组进行difference得出每个数组不一样的部分,最后整合即为结果。

function xor0(...arrays){
  const map = {};
  const all = arrays.reduce((pre, cur) => {
    cur.forEach(item=>{
      map[item] = map[item]?map[item]+1:1
    })
    return pre.concat(cur)
  }, [])
  let index = 0;
  const result = [];
  while(index<all.length){
    const cur = all[index];
    if(map[cur]===1){
      result.push(cur);
    }
  }
  return result;
}
function difference(arr, ...rest) {
  // 扁平化rest
  const target = rest.reduce((pre, cur) => {
    return pre.concat(cur)
  }, [])
  return arr.filter(item => !target.includes(item))
}
function xor(...arrays){
  const len = arrays.length;
  const result = Array(len);
  let index = 0;
  while(index<len){
    let oIndex = 0;
    while(oIndex<len){
      if(oIndex!==index){
        result[index] = difference(result[index]||arrays[index], arrays[oIndex])
      }
      oIndex++
    }
    index++;
  }
  return result.reduce((pre, cur)=>{
    return pre.concat(cur);
  }, [])
}
function differenceBy(arr, ...args) {
  if(args.length<2) {
    throw new Error('iteratee missing or target array missing')
  }
  const rest = args.slice(0, args.length-1)
  const keyOrFunc = args[args.length-1]
  let iteratee;
  if(typeof keyOrFunc === 'string') {
    iteratee = (item) => item[keyOrFunc]
  }else{
    iteratee = keyOrFunc
  }
  // 扁平化rest
  const target = rest.reduce((pre, cur) => {
    return pre.concat(cur.map(i=>iteratee(i)))
  }, []);
  return arr.filter(item => !target.includes(iteratee(item)))
}

function xorBy(...args){
  const iteratee = args[args.length-1];
  const it = typeof iteratee === 'string'?x=>x[iteratee]:iteratee;
  const arrays = args.slice(0, args.length-1);
  const len = arrays.length;
  const result = Array(len);
  let index = 0;
  while(index<len){
    let oIndex = 0;
    while(oIndex<len){
      if(oIndex!==index){
        result[index] = differenceBy(result[index]||arrays[index], arrays[oIndex], it)
      }
      oIndex++
    }
    index++;
  }
  return result.reduce((pre, cur)=>{
    return pre.concat(cur);
  }, [])
}

function differenceWith(arr, ...args) {
  if(args.length<2) {
    throw new Error('iteratee missing or target array missing')
  }
  const rest = args.slice(0, args.length-1)
  const comparator = args[args.length-1]
 
  // 扁平化rest
  const target = rest.reduce((pre, cur) => {
    return pre.concat(cur)
  }, []);
  return arr.filter(item => {
    for(let i=0;i<target.length;i++) {
      if(comparator(target[i], item)) {
        return false;
      }
    }
    return true
  })
}

function xorWith(...args){
  const iteratee = args[args.length-1];
  const arrays = args.slice(0, args.length-1);
  const len = arrays.length;
  const result = Array(len);
  let index = 0;
  while(index<len){
    let oIndex = 0;
    while(oIndex<len){
      if(oIndex!==index){
        result[index] = differenceWith(result[index]||arrays[index], arrays[oIndex], iteratee)
      }
      oIndex++
    }
    index++;
  }
  return result.reduce((pre, cur)=>{
    return pre.concat(cur);
  }, [])
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章