Ramda 找出水仙花数

146 阅读1分钟

什么是水仙花数

介绍

一个 n 位数,各数位的 n 次幂之和等于自身,就叫水仙花数。

比方 153 这个 3 位数:153=13+53+33153 = 1^3 + 5^3 + 3^3

思路

找所有 n 位水仙花数

假设 n = 3

  1. 查找范围在 100~1000,即 Math.pow(10, 2) ~ Math.pow(10, 3)

    Math.pow(10, n-1) ~ Math.pow(10, n)

  2. 对范围内各数 num,判断自身是否等于求出的

求和

  1. num 分割得到 Array<number>,即各数位上的数
  2. 求出各数位 3 次幂
  3. 求和

下面一步一步实现

分割数字

  • 方案1:数字转字符串再分割

    const splitNum = R.compose( R.map(Number), R.split(''), R.toString );
    
  • 方案2:持续对 10 取余

    /**
     * n = 153
     * 153 % 10 -> 3
     *  15 % 10 -> 5
     *   1 % 10 -> 1
     */
    function splitNum(num) {
      function go(acc, x) {
        return 0 === x
          ? acc
          : go( [x % 10].concat(acc), Math.trunc(x / 10) );
      }
    
      return go([], num);
    }
    

3 次幂之和

const pow = R.curry( (y, x) => Math.pow(x, y) );
R.compose( R.sum, R.map(pow(3)), splitNum )(153);
// 153

成品

function NarcissisticNums(n) {
  const pow = R.curry( (y, x) => Math.pow(x, y) );
  
  function splitNum(num) {
    function go(acc, x) {
      return 0 === x
        ? acc
        : go( [x % 10].concat(acc), Math.trunc(x / 10) );
    }
  
    return go([], num);
  }

  const sumDigitsPowN = R.compose( R.sum, R.map(pow(n)), splitNum );
  
  const isNarcissisticNum = R.converge( R.equals, [R.identity, sumDigitsPowN] );
  
  return R.filter(isNarcissisticNum, R.range( pow(n-1, 10), pow(n, 10) ));
}

NarcissisticNums(3);
// [153, 370, 371, 407]

NarcissisticNums(4);
// [1634, 8208, 9474]