兩個函數式處理大數相加的要領

處理大數相加的要領有許多,網上很輕易搜到,下面引見兩種,一種是在網上抄的,一種是本身想的,我將他們都用函數式的體式格局重寫了一遍。

這類是在網上抄的,確實異常簡約

function add(a,b) {
  let res='', c=0;
  a = a.split('');
  b = b.split('');
  while (a.length || b.length || c){
    c += ~~a.pop() + ~~b.pop();
    res = c % 10 + res;
    c = c>9;
  }
  return res.replace(/^0+/,'');
}

函數式重寫,重點在尾遞歸,這是在函數式編程中替代while的寫法。

let compose = (f, g) => (...args) => f(g(...args));
let addUnit = a => b => b + a;
let myPop = a => a.pop();  // 有副作用
let myNumber = a => ~~a;
let remainderTen = x => x % 10;
let isGreeterNine = x => x > 9;
let replaceHeadZero = x => x.replace(/^0+/, "");
let pAndN = compose(myNumber, myPop);
let loop = (a, b, res, c) => {    //尾遞歸,即在函數末端自挪用
  if (!a.length && !b.length && !c) return res;
  let getC = compose(addUnit(pAndN(b)), addUnit(pAndN(a)));
  let getEes = compose(addUnit(res), remainderTen);
  return loop(a, b, getEes(getC(c)), isGreeterNine(getC(c)));
}
let add = (a, b) => compose(replaceHeadZero, loop)(a.split(""), b.split(""), "", 0);

本身想的

運用累加器完成

function add(a, b) {
  a = a.split('').reverse();
  b = b.split('').reverse();
  function addMap(aArrayIns, bArrayIns) {
    return aArrayIns.reduce((accumulator, currentValue, index) => {
      let c = ~~bArrayIns[index] + ~~currentValue + ~~accumulator[index];
      if (c >= 10) {
        accumulator[index] = (c - 10).toString();
        accumulator.push('1');
      } else {
        accumulator[index] = c.toString();
      }
      return accumulator;
    }, []).reverse().join('');
  }
  return a.length >= b.length ? addMap(a, b) : addMap(b, a);
}

函數式重寫

let compose = (f, g) => x => f(g(x));
let myReverse = x => {
  let [...y] = x;
  return y.reverse();
};
let mySplit = x => x.split("");
let myToString = x => x.toString();
let myPushOne = x => {
  let [...y] = x;
  y.push("1");
  return y;
}
let setValue = index => value => targetArray => {
  let [...y] = targetArray;
  y[index] = value;
  return y;
}
let splitAndReverse = compose(myReverse, mySplit);
let myReduce = x => y => y.reduce(fnHandleAdd(splitAndReverse(x)), []);
let fnHandleAdd = a => (accumulator, currentValue, index) => {
  let c = ~~a[index] + ~~currentValue + ~~accumulator[index];
  return c >= 10
    ? compose(myPushOne, setValue(index)(myToString(c - 10)))(accumulator)
    : setValue(index)(myToString(c))(accumulator);
};

let addMap = (a, b) => compose(compose(R.join(""), myReverse), compose(myReduce(b), splitAndReverse))(a);
let add = (a, b) => a.length >= b.length ? addMap(a, b) : addMap(b, a);

下面這類寫法,很不文雅

let addMap = (a, b) => compose(compose(R.join(""), myReverse), compose(myReduce(b), splitAndReverse))(a);

最好compose能夠完成組合恣意個函數,結果以下

let addMap = (a, b) => compose(R.join(""), myReverse, myReduce(b), splitAndReverse)(a);

完成思緒在:https://github.com/zhuanyongx…

我在github https://github.com/zhuanyongx…

    原文作者:磚用西瓜
    原文地址: https://segmentfault.com/a/1190000015049323
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞