我注意到如果我使用ramda
,有时候在尝试为我导出的方法编写Jest
测试时会遇到问题。我已经将问题归结为以下测试和两个基本的减速器功能。我已将它们发布在gist
上,以免用代码堵塞这个问题。
https://gist.github.com/beardedtim/99aabe3b08ba58037b20d65343ed9d20
我使用ramda
reducer收到以下错误:
● counter usage › counter counts the words and their index in the given list of words
expect(received).toEqual(expected)
Expected value to equal:
[{"count": 3, "indexes": [0, 2, 4], "value": "a"}, {"count": 1, "indexes": [1], "value": "b"}, {"count": 1, "indexes": [3], "value": "c"}]
Received:
[{"count": 15, "indexes": [0, 2, 4, 0, 2, 4, 0, 2, 4, 0, 2, 4, 0, 2, 4], "value": "a"}, {"count": 5, "indexes": [1, 1, 1, 1, 1], "value": "b"}, {"count": 5, "indexes": [3, 3, 3, 3, 3
], "value": "c"}]
这让我相信ramda
的缩减是保持某种状态或彼此分享words
。我不确定这是怎么回事。任何人都知道我应该谷歌搜索或其他处理此事件的文档/示例?
答案 0 :(得分:3)
状态数组(final
)硬连线到reduceWithIndex
。对此函数的所有调用都共享相同的final
数组。
试试这个:
import { reduce, addIndex } from 'ramda';
const reduceWithIndex = addIndex(reduce)((final, word, index) => {
const found = final.find(({ value }) =>
value.toLowerCase() === word.toLowerCase()
);
if (found) {
found.count++;
found.indexes.push(index);
} else {
final.push({
value: word.toLocaleLowerCase(),
count: 1,
indexes: [index],
});
}
return final;
});
export default words => reduceWithIndex([], words);
答案 1 :(得分:1)
托马斯的诊断是正确的。但我会选择一个略有不同的修复:
import { reduce, addIndex, append } from 'ramda';
const reduceWithIndex = addIndex(reduce);
export default reduceWithIndex((final, word, index) => {
const found = final.find(({ value }) =>
value.toLowerCase() === word.toLowerCase()
);
if (found) {
found.count++;
found.indexes.push(index);
return final;
}
return append({
value: word.toLocaleLowerCase(),
count: 1,
indexes: [index],
}, final);
}, []);
函数式编程涉及很多事情,但最重要的一个是不可变数据结构。虽然没有什么能阻止你改变累加器对象并将它传回你的reducer函数,但我发现它的风格很差。相反,总是返回一个新对象,你不会遇到这样的问题。 Ramda的所有功能都是基于这个原则构建的,因此在使用append
时,您会自动获得一个新列表。
我还建议更改if
- 块以避免found
对象的内部变异。我将此作为练习留下,但如果难以做到,请随意ping。
您可以在Ramda REPL中看到 original solution 与 altered version 之间的区别。