javascript - 使用 ramda.js 将命令式风格转换为函数式风格

标签 javascript functional-programming ramda.js

我正在编写使用命令式样式将数字数组转换为新数据列表的代码,但我想使用像 ramdajs 这样的 javascript 库将其转换为函数式样式

代码背景 假设美元值(value) 共有 5 个硬币,25 美元,20 美元,... 1 美元。我们将不得不把钱换成美元硬币。用最少的金币

const data = [25, 20, 10, 5, 1];
const fn = n => data.map((v) => {
    const numberOfCoin = Number.parseInt(n / v, 10);
    const result = [v, numberOfCoin];
    n %= v;
    return numberOfCoin ? result : [];
  }).filter(i => i.length > 0);

这段代码的结果应该是

fn(48) => [[25, 1], [20, 1], [1, 3]]
fn(100) => [[25, 4]]

最佳答案

我认为您已经有了一个很好的开始,但为了使其更具功能性,我需要进行一些更改:

  1. 使用表达式而不是语句(例如没有return)
  2. 不改变数据(例如没有n %= v)

你不一定需要 Ramda:

const coins = value =>
  [25, 20, 10, 5, 1].reduce(([acc, val], cur) =>
    val < cur ? [acc, val] : [[...acc, [cur, Math.floor(val / cur)]], val % cur],
    [[], value]
  )[0];


console.log(coins(48));
console.log(coins(100));

如果您发现自己使用 map 然后使用 filter,您很可能需要 reduce。在我上面的函数 coins 中,迭代器返回一个数组,其中包含一对硬币数组和硬币数量以及每个步骤的减少值。

请注意,在每个步骤中,我都使用解构赋值来捕获对数组和单个参数中的减少值。

现在,当然也可以为此使用 Ramda:

const {compose, filter, last, mapAccum, flip} = R;

const mapIterator = (a, b) => [a % b, [b, Math.floor(a / b)]];
const withCoins = ([coins, number]) => number > 0;
const coins = compose(filter(withCoins), last, flip(mapAccum(mapIterator))([25, 20, 10, 5, 1]));

console.log(coins(48));
console.log(coins(100));
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.min.js"></script>

编辑:正如 Scott 正确指出的那样,我上面的任何解决方案都会给您带来最少的改变。

事实证明,这比我预期的要复杂得多,我确定了一个我确信可以改进的解决方案:

我定义了 5 组硬币:

  1. [1]
  2. [5, 1]
  3. [10, 5, 1]
  4. [20, 10, 5, 1]
  5. [25, 20, 10, 5, 1]

我计算每组产生多少变化,只保留产生最少的那一个。

例如改变30:

  1. 1×30
  2. 5×6
  3. 10 × 3
  4. 20 × 1, 10 × 1(保留这组)
  5. 25 × 1, 5 × 1

const {compose, pipe, sum, map, last, head, mapAccum, curry, flip, applyTo, sortBy, reject, not} = R;
const numCoins = compose(sum, map(last));
const changeFn = curry((coins, num) => mapAccum((cur, coin) => [cur % coin, [coin, Math.floor(cur / coin)]], num, coins)[1]);
const change1 = changeFn([1]);
const change2 = changeFn([5, 1]);
const change3 = changeFn([10, 5, 1]);
const change4 = changeFn([20, 10, 5, 1]);
const change5 = changeFn([25, 20, 10, 5, 1]);

const change = pipe(
  applyTo,
  flip(map)([
    change1,
    change2,
    change3,
    change4,
    change5]),
  sortBy(numCoins),
  head,
  reject(compose(not, last)));

console.log(change(30));
console.log(change(40));
console.log(change(48));
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.min.js"></script>

关于javascript - 使用 ramda.js 将命令式风格转换为函数式风格,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54759788/

相关文章:

functional-programming - 为什么状态单子(monad)中需要平面图?

javascript - 使用 Ramda 处理 Promise 和 Wait

javascript - 使用 Ramda 减少 "position"属性

javascript - 对象函数在 JS 中不起作用

swift - 如何在 Swift 中将 "append"设置为不可变字典?

javascript - ResponsiveSlides 无法正常工作

javascript - 关于 JavaScript promises 和 "then"语句的新手问题

javascript - 使用 Ramda,你如何针对二进制函数进行组合?

javascript - 请解释这个奇怪的 Javascript 行

javascript - meteor .js : ReferenceError: window is not defined