2017-01-12 14 views
2

ここに私が運動していたマッピング関数があります。.filter()関数をJavaScriptで再帰的に表現するには?

var list = [1,2,3,4,5]; 

function isOdd(v) { 
    return v % 2 == 1; 
} 

function exclude(arr, fn) { 
    var myList = []; 
    for (var i = 0; i < arr.length; i++) { 
     if (fn(arr[i])) { 
      myList.push(arr[i]); 
     } 
    }; 
    return myList; 
} 

私は、再帰的な解決策でforループを交換したいが、私は、私は再帰でそれを解決することができますどのようにライン2で各関数呼び出しで新しいリストを開始して以来、それは適切な配列を生成しないのですか?ここに私が得た最も近いものがあります。

function exclude(arr, fn) { 
    let myList = []; 
    if (arr.length = 1) { 
     if (fn(arr[0])) { 
      return myList.push(arr[0]); 
     } 
    } else { 
     return myList.push(exclude(arr.slice(1), fn)); 
    } 
} 

console.log(exclude(list, isOdd)); 
+2

'list.filter(isOdd)'を使いたくない理由はありますか? –

答えて

3

はこの1つのソリューションを試してみてください。あなたの実装を少し変更しました。

function exclude(arr, fn, output) { 
 
    output || (output = []); 
 
    
 
    if(!arr.length) { 
 
    return output; 
 
    } 
 
    
 
    if (fn(arr[0])) { 
 
    output.push(arr[0]); 
 
    } 
 

 
    return exclude(arr.slice(1), fn, output); 
 
} 
 

 
console.log(exclude([1,2,3,4,5,6,7,8,9], function(i) { return i % 2; }));

1
if (arr.length = 1) { 

これは、その中に1つの以上の項目がある場合に効果的配列をトリミング、arr.lengthに1を代入します。おそらくarr.length ===を意味しています。

第二に、Array#pushメソッドは、配列の新しい長さではなく、配列そのものを返しますので、あなたが持っている場所:

return myList.push(arr[0]); 

は、あなたはおそらくしたい:

myList.push(arr[0]); 
return myList; 
0

あなたが元の配列を変更し、各再帰呼び出しに元の配列のコピーを作成したくない場合は、ここで醜い解決策になる可能性が

function exclude(arr, fn, result, index) { 
    if (!result) { 
     result = []; 
     index = -1; 
    } 
    index++; 
    if (index < arr.length && fn(arr[inndex])) 
     result.push(arr[index]); 
    if (index === arr.length) 
     return result; 
    return exclude(arr, fn, result, index); 
} 

console.log(exclude([1,2,3,4], function(i){return i%2===0;})); // prints "2,4" 
0

私見あなたの例は再帰に本当に適合しません。これは、ここでループを使用するためには、はるかに読みやすく、エラーが発生しにくいです。再帰は、コンテキストやスコープのためにJSで簡単に処理できないことがあります。テストケースとして実際にやりたければ、配列を変換しないことをお勧めします。遅くてあまり使用されません。とにかく最後には、forループと同じ動作で終了しますが、効率は低下します。ここでの例です:

var list = [1,2,3,4,5]; 
 

 
function isOdd(v) { 
 
    return v % 2 == 1; 
 
} 
 

 
function exclude(arr, fn, optionalIndex) { 
 
    var myList = []; 
 
    if(!optionalIndex){ 
 
     optionalIndex = 0; 
 
    } 
 
    if(optionalIndex < arr.length){ 
 
     if(fn(arr[optionalIndex])){ 
 
      myList.push(arr[optionalIndex]); 
 
     } 
 
     myList = myList.concat(exclude(arr, fn, optionalIndex + 1)); 
 
    } 
 
    return myList; 
 
} 
 

 
console.log(exclude(list, isOdd));

あなたはこの配列をフィルタリングするforループを使用してバージョンを使用して、例えば、実際の再帰ケースでそれを実行しようとすることは実際にはもっと興味深いものになるだろう

var list = [1、2、3、[0,1,2、[0,10,20,30]、4]、5、[1,2,3] ];ちょうどそれの楽しみのため

0

、1行のソリューション:

function exclude(a, fn, c) { 
    return (c = c || (c !== 0 ? a.length - 1 : c)) >= a.splice(c, fn(a[c]) ? 0:1)*0 ? exclude(a, fn, c - 1) : a; 
} 

スニペット:JavaScriptの以来

var list = [0,1,2,3,4,5]; 
 

 
function isOdd(v) { 
 
    return v % 2 != 0; 
 
} 
 

 
function exclude(a, fn, c) { 
 
    return (c = c || (c !== 0 ? a.length - 1 : c)) >= a.splice(c, fn(a[c]) ? 0:1)*0 ? exclude(a, fn, c - 1) : a; 
 
} 
 

 
console.log(exclude(list, isOdd));

0

は末尾呼び出しの削除を超える再帰的な解決策を持っていません大きな配列はあなたのスタックを爆破するでしょう。しかし、問題への機能的かつ再帰的なアプローチは次のようになります。

function filter(arr, fn) { 
    var stopAt = arr.length; 
    function helper (index, acc) { 
     return index === stopAt ? 
       acc : 
       helper(index+1, fn(arr[index]) ? 
           acc.concat([arr[index]]) : 
           acc) ; 
    } 
    return helper(0, []); 
} 

もちろん、これは決して実動コードであってはなりません。内部構造を突然変異させることを可能にしながら機能的なインターフェースを持つことは、おそらく最良のアプローチです。機能ライブラリのソースを参照する場合は、Rambdaが内部状態を変更することがわかります。

関連する問題