一天一個仿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);
  }, [])
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章