R.pipe 中对 R.reduce 的 2 次连续调用之间的累加器未重置
Accumulator not reset between 2 consecutive calls to R.reduce in a R.pipe
考虑这段代码,使用 Ramda 0.21.0:
var iteratee = (acc, [k, v]) => {
acc[k] = ++v;
return acc
}
var foo = R.pipe(
R.toPairs,
R.reduce(iteratee, {})
)
console.log(foo({ a: 1, b: 2})) // { a: 2, b: 3 }
console.log(foo({ c: 3, d: 4})) // { a: 2, b: 3, c: 4, d: 5 }
为什么第二次调用 foo
显示 { a: 2, b: 3, c: 4, d: 5 }
而不是 { c: 4, d: 5 }
?
是否正在进行某种记忆?我希望每次应用 foo 时 acc
的初始值都会重置为 {}
。
这个答案主要是对 @iofjuupasli
的评论的扩展
问题是累加器对象的突变。你在 foo
的定义中创建一个,它在每次调用时重复使用,然后你在 iteratee
中更新它(可怕的名字,恕我直言。称它为 bar
或其他东西。:-)) .有几种方法可以解决这个问题。一种可能是确保在每次调用 foo
:
时传递一个新的累加器
var iteratee = (acc, [k, v]) => {
acc[k] = ++v;
return acc
}
var foo = R.pipe(
R.toPairs,
list => R.reduce(iteratee, {}, list)
)
foo({ a: 1, b: 2}); //=> {"a": 2, "b": 3}
foo({ c: 3, d: 4}); //=> {"c": 4, "d": 5}
这可行,但感觉不尽如人意。也许更有帮助的是避免在每次传递时改变累加器对象。 assoc
将创建一个新对象,尽可能多地重用前一个对象:
var iteratee = (acc, [k, v]) => R.assoc(k, v + 1, acc)
var foo = R.pipe(
R.toPairs,
R.reduce(iteratee, {})
);
foo({ a: 1, b: 2}); //=> {"a": 2, "b": 3}
foo({ c: 3, d: 4}); //=> {"c": 4, "d": 5}
这看起来更干净了。但实际上 Ramda 有一个更简单的解决方案。 map
function treats objects as functors to be mapped over. Combining this with inc
,它只是增加一个值,我们可以这样做:
var foo = R.map(R.inc);
foo({ a: 1, b: 2}); //=> {"a": 2, "b": 3}
foo({ c: 3, d: 4}); //=> {"c": 4, "d": 5}
感觉真的很干净!
考虑这段代码,使用 Ramda 0.21.0:
var iteratee = (acc, [k, v]) => {
acc[k] = ++v;
return acc
}
var foo = R.pipe(
R.toPairs,
R.reduce(iteratee, {})
)
console.log(foo({ a: 1, b: 2})) // { a: 2, b: 3 }
console.log(foo({ c: 3, d: 4})) // { a: 2, b: 3, c: 4, d: 5 }
为什么第二次调用 foo
显示 { a: 2, b: 3, c: 4, d: 5 }
而不是 { c: 4, d: 5 }
?
是否正在进行某种记忆?我希望每次应用 foo 时 acc
的初始值都会重置为 {}
。
这个答案主要是对 @iofjuupasli
的评论的扩展问题是累加器对象的突变。你在 foo
的定义中创建一个,它在每次调用时重复使用,然后你在 iteratee
中更新它(可怕的名字,恕我直言。称它为 bar
或其他东西。:-)) .有几种方法可以解决这个问题。一种可能是确保在每次调用 foo
:
var iteratee = (acc, [k, v]) => {
acc[k] = ++v;
return acc
}
var foo = R.pipe(
R.toPairs,
list => R.reduce(iteratee, {}, list)
)
foo({ a: 1, b: 2}); //=> {"a": 2, "b": 3}
foo({ c: 3, d: 4}); //=> {"c": 4, "d": 5}
这可行,但感觉不尽如人意。也许更有帮助的是避免在每次传递时改变累加器对象。 assoc
将创建一个新对象,尽可能多地重用前一个对象:
var iteratee = (acc, [k, v]) => R.assoc(k, v + 1, acc)
var foo = R.pipe(
R.toPairs,
R.reduce(iteratee, {})
);
foo({ a: 1, b: 2}); //=> {"a": 2, "b": 3}
foo({ c: 3, d: 4}); //=> {"c": 4, "d": 5}
这看起来更干净了。但实际上 Ramda 有一个更简单的解决方案。 map
function treats objects as functors to be mapped over. Combining this with inc
,它只是增加一个值,我们可以这样做:
var foo = R.map(R.inc);
foo({ a: 1, b: 2}); //=> {"a": 2, "b": 3}
foo({ c: 3, d: 4}); //=> {"c": 4, "d": 5}
感觉真的很干净!