関数型プログラミングプリンシパルを使用して汎用reduce関数からflatten関数を生成するときに、配列flatten関数から誤った値を取得するのに問題があります。これは、呼び出し内の再帰に問題があるためだと思いますが、機能している関数と機能していない関数の両方の関数シグネチャが同じである必要があるため、それを超える方法がわかりません。
助けてくれてありがとう。
var data = [['one','two','three'], ['four', 'five', ['six']], 'seven', ['eight', 'nine']];
// here is an example of flatten that works perfectly. it takes an array and reduces
// the internal arrays to a single flat array
function flatten( arr ){
return arr.reduce(function( ret, curr ){
if( Array.isArray( curr ) ){
ret = ret.concat( flatten( curr ) );
} else {
ret.push( curr );
}
return ret;
}, []);
}
// here is what I am trying to achieve. This one combines my reduction functon with the
// functional `reduceWith` function. The code signature is exactly the same, however the
// end result is different.
// `functionalFlatten` does resolve to the correct function inside
var functionalFlatten = reduceWith(function( ret, curr ){
if( Array.isArray( curr ) ){
ret = ret.concat( functionalFlatten( curr ) );
} else {
ret.push( curr );
}
return ret;
}, []);
// this function will return a functional reduction function
function reduceWith( fn, initial ) {
return function _reduceWith( arr ) {
return Array.prototype.reduce.call(arr, fn, initial || []);
}
}
console.log('data', data);
console.log('functionalFlatten', functionalFlatten );
console.log('normal', flatten( data ));
console.log('fuctional', functionalFlatten( data ));
<script src="http://codepen.io/synthet1c/pen/WrQapG.js"></script>
コードにいくつか変更を加えました。これは機能します:
var data = [
['one','two','three'],
['four', 'five', ['six']],
'seven',
['eight', 'nine']
]
function flatten(arr) {
return arr.reduce(function(ret, curr) {
return ret.concat(Array.isArray(curr) ? flatten(curr) : [curr])
}, [])
}
var functionalFlatten = reduceWith(function(ret, curr) {
return Array.prototype.concat.call(ret, Array.isArray(curr) ? functionalFlatten(curr) : [curr])
}, [])
// I assume you want to use .call to keep it functional or what ever
// But I would just do it like this:
var _functionalFlatten = reduceWith(function(ret, curr) {
return ret.concat(ret, Array.isArray(curr) ? functionalFlatten(curr) : [curr])
}, [])
function reduceWith(fn, initial) {
return (function (arr) {
return Array.prototype.reduce.call(arr, fn, initial)
})
}
// Again, keep it simple...
function _reduceWith(fn, initial) {
return (function (arr) {
return arr.reduce(fn, initial)
})
}
// You had this...
function reduceWith( fn, initial ) {
// You don't need to name this function:
return function _reduceWith( arr ) {
// Let's keep this in line original function, so remove the default:
return Array.prototype.reduce.call(arr, fn, initial || []);
}
}
console.log('data', data)
console.log('functionalFlatten', functionalFlatten)
console.log('normal', flatten(data))
console.log('fuctional', functionalFlatten(data))
さて、実際の問題に...
var functionalFlatten = reduceWith(function( ret, curr ){
if( Array.isArray( curr ) ){
ret = ret.concat( functionalFlatten( curr ) );
} else {
// This is your culprit:
ret.push( curr ); // push will mutate ret
}
return ret;
}, []);
reduceWith
一度だけ呼び出されます(functionalFlatten
定義されている場合)。ret.push(curr)
変異する可能性がありますinitial
ここに証拠があります...
function reduceWithMutationSafe(fn, initial) {
return (function (arr) {
// Clone initial, so that the original can't be mutated:
var clonedInitial = eval(JSON.stringify(initial))
return arr.reduce(fn, clonedInitial)
})
}
var functionalFlatten = reduceWithMutationSafe(function(ret, curr) {
if(Array.isArray(curr)) {
ret = ret.concat(functionalFlatten(curr))
} else {
ret.push(curr)
}
return ret
}, [])
これは、functionalFlatten
以前
ret.push(curr)
とまったく同じでクローンinitial
が変更されても機能しますが、元のクローンには影響しません。
しかし、この最後のコードは単なる証拠です。を使用する必要はありませんreduceWithMutationSafe
。
この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。
侵害の場合は、連絡してください[email protected]
コメントを追加