将整数分解成块,在功能上

时间:2017-03-21 16:03:19

标签: javascript functional-programming

考虑将毫秒分解为可读时间单位的问题。想象一下,你有一个能够做到这一点的功能

> breakupMillis(100000000)
Array [ 0, 40, 46, 3, 1 ]

意味着1亿毫秒完全是1天,3小时,46分钟和40秒。

该函数可以通过接受模数数组来推广,比如

> breakup(100000000, [1000, 60, 60, 24]) 
Array [ 0, 40, 46, 3, 1 ]

该功能可以(假设地)用于其他事情:

> breakup(1000, [8, 8, 8]) 
Array [ 0, 5, 7, 1 ]

意味着十进制中的1000是八进制中的01750。

这是我写的这个函数:

const breakup = (n, l) => l.map(p => 
    { const q = n % p; n = (n - q) / p; return q; }).concat(n);

这个功能很好,甚至是引用透明的,但我有两个完全美观的抱怨。

  • map。这感觉就像reduce的工作,虽然我不知道如何。
  • 重写变量n。我根本不喜欢使用var;使用秘密 var会让情况变得更糟。

我的问题只是关于第二个问题。如何重新编写函数,使其不使用变量(实际上有所不同)?如果map消失,我会将其视为肉汁。

3 个答案:

答案 0 :(得分:2)

这是另一种方法,你可以使用递归过程和一个小助手quotrem - 给出分子n和分母d,返回[<quotient>, <remainder>] < / p>

const quotrem = (n, d) => [n / d >> 0, n % d]

const breakup = (n, [x,...xs]) => {
  if (x === undefined) {
    return [n]
  }
  else {
    let [q, r] = quotrem(n, x)
    return [r, ...breakup(q, xs)]
  }
}

console.log(breakup(1000, [8, 8, 8]))
// [ 0, 5, 7, 1 ]

console.log(breakup(100000000, [1000, 60, 60, 24]))
// [ 0, 40, 46, 3, 1 ]

如果您对结构化阵列不太满意,可以添加一些帮助器(isEmptyheadtail)以与更多阵列进行交互明确的方式

const isEmpty = xs => xs.length === 0
const head = xs => xs[0]
const tail = xs => xs.slice(1)
const quotrem = (n, d) => [n / d >> 0, n % d]

const breakup = (n, xs) => {
  if (isEmpty(xs)) {
    return [n]
  }
  else {
    let [q, r] = quotrem(n, head(xs))
    return [r, ...breakup(q, tail(xs))]
  }
}

console.log(breakup(1000, [8, 8, 8]))
// [ 0, 5, 7, 1 ]

console.log(breakup(100000000, [1000, 60, 60, 24]))
// [ 0, 40, 46, 3, 1 ]

答案 1 :(得分:0)

  

这感觉就像是reduce的工作,虽然我不知道如何。

迭代数组的所有内容都可以使用reduce完成: - )

我们需要通过两件事(对于累加器):我们仍有休息的数字和结果列表。我们可以使用ES6解构和数组作为元组:

function breakup(n, units) {
    const [n, res] = units.reduce(([n, res], u) => {
        const q = n % u;
        res.push((n-q) / u);
        return [q, res];
    }, [n, units]);
    return [n, ...res];
}

push仍然很难看。不仅因为它变异(我们也可以使用concat),但我们真正想要的是一个抽象它的函数。不幸的是,JS中不存在这些 - 我们正在寻找scanmapping accumulation。我们可以写

function breakup(n, units) {
    const [rest, res] = units.mapAccum((n, u) => {
        const q = n % u;
        return [q, (n-q) / u];
    }, [n, units]);
    return [...res, rest];
}
function breakup(n, units) {
    const mods = units.scan((n, u) => Math.floor(n/u), units);
    return mods.map((q, i) => i<units.length ? q % units[i] : q);
}

我会将这些(功能,高效,可读等)的实现留给读者作为练习。

答案 2 :(得分:0)

我会建议这段代码:

Observable<MyResponseStream>