2016-04-15 1 views
2

でR.reduceに2回の連続呼び出しの間にリセットされない:アキュムレータは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 }に2回目の呼び出し?

何らかのメモ処理が行われていますか?私はaccの初期値がfooが適用される度に{}にリセットされると期待します。

+0

初期値を変更します。 Ramdaはそれを気にせず、反復の開始時にクローンを作成しません – iofjuupasli

+0

また、マップ関数を使ってあなたの例を行うことができます – iofjuupasli

答えて

4

この答えは、ほとんどの問題は、アキュムレータオブジェクトの突然変異である@iofjuupasli

によってコメントに拡張します。あなたはfooの定義で1つを作成し、それはすべての呼び出しで再利用され、iteratee(恐ろしい名前、IMHO。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} 

これは動作しますが、満足のいかない感じ。おそらく、各パスでアキュムレータオブジェクトを変更するのを避けるほうが、もっと役立つでしょう。これは、クリーンなようだ

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} 

assocは、可能な限り、以前の1のできるだけ多くを再利用し、新しいオブジェクトを作成します。しかし実際、Ramdaははるかに単純なソリューションを持っています。 map関数は、オブジェクトをマッピングするファンクタとして扱います。

var foo = R.map(R.inc); 

foo({ a: 1, b: 2}); //=> {"a": 2, "b": 3} 
foo({ c: 3, d: 4}); //=> {"c": 4, "d": 5} 

をそして、それは本当にきれいな感じ:単純に値をインクリメントしinc、でこれを組み合わせることで、私たちはこれを行うことができます!

+0

なぜ 'reduce'は同じアキュムレータを異なる呼び出しで再利用するのですか?関数を作成できるという目的は、関数を再利用することなので、私にとっては意味がありません。 – dawnstar

+1

'reduce'はあなたが渡すアキュムレータを使います。この場合、ユーザーは反復ステップですべての呼び出しで同じ参照を再利用していました。その組み合わせは致命的である可能性がありますが、ラムダが各呼び出しで使用された参照を複製する場合、唯一の他のオプションである場合、供給されたアキュムレータを変更することを希望するユーザーはその動作を取得できませんでした。私は他の美味しいオプションは見ません。あなたは? –

+0

それは多くの意味があります、説明に感謝します。 – dawnstar

関連する問題