2016-04-15 37 views
2

2個連續通話R.reduce考慮這個代碼之間不復位,使用Ramda 0.21.0:累加器在R.pipe

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的初始值重置爲{}

+0

您可以改變初始值。 Ramda並不關心它,並且在迭代開始時不會生成克隆。 – iofjuupasli

+0

也可以使用map函數完成示例 – iofjuupasli

回答

4

這個答案大多發表的意見@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} 

這似乎更清潔。但事實上拉姆達有一個更簡單的解決方案。 map函數將對象視爲待映射的函子。與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} 

那種感覺真的很乾淨!

+0

爲什麼'reduce'在不同的調用中重複使用相同的累加器?這對我來說沒有意義,因爲能夠編寫函數的目的是重用它們。 – dawnstar

+1

'reduce'使用您傳遞給它的累加器。在這種情況下,用戶在每次調用*和*時重複使用相同的引用,並在迭代步驟中對其進行變更。這種組合可能是致命的......但是,如果Ramda克隆每次調用時使用的引用 - 唯一的另一種選擇 - 那麼希望減少變異提供的累加器的用戶無法獲得該行爲。我沒有看到任何其他可口的選項。你做? –

+0

這很有道理,謝謝你的解釋。 – dawnstar