2016-04-16 8 views
2

次の関数は(再帰的にそれを検索して)ネストされた配列にオブジェクトを追加:次の再帰関数を純粋な関数にするには?

function appendDeep (arr, obj, newObj) { 
    if (arr.indexOf(obj) !== -1) { 
    arr.splice(arr.indexOf(obj) + 1, 0, newObj) 
    } else { 
    arr.map(item => { 
     if (item.children) spliceDeep(item.children, obj) 
    }) 
    } 
} 

例:

const colors = { 
    children: [ 
    { 
     name: 'white', 
    }, 
    { 
     name: 'yellow', 
     children: [ 
     { 
      name: 'black' 
     } 
     ] 
    } 
    ] 
} 

const color = { 
    name: 'black' 
} 

const newColor = { 
    name: 'brown' 
} 

appendDeep(colors.children, color, newColor) 

結果:

children: [ 
    [ 
     { 
     name: 'white', 
     }, 
     { 
     name: 'yellow', 
     children: [ 
      { 
      name: 'black' 
      }, 
      { 
      name: 'brown' 
      } 
     ] 
     } 
    ] 
    ] 

をあなたがappendDeepを見ることができるように副作用を返す。 arrを変更します。だから私は(そう関数が純粋になる)の代わりに、配列を返すことにしました:

function findDeep (arr, obj) { 
    if (arr.indexOf(obj) !== -1) { 
    console.log(arr) 
    return arr 
    } else { 
    arr.map(item => { 
     if (item.children) findDeep(item.children, obj) 
    }) 
    } 
} 

そして、このような新しい機能を使用します。

const newArr = findDeep(colors.children, color) 
newArr.splice(newArr.indexOf(color) + 1, 0, newColor) 

をしかし、私はこのエラーを取得する:

bundle.js:19893 Uncaught TypeError: Cannot read property 'splice' of undefined 

私は間違っていますか?

(注:ここではCodePenだ)

(注2:。。console.log(arr)は、ネストされた子どもたちを返すんが、何らかの理由で、彼らは機能のundefined外になる)

+0

'color'と' newColor'を有効なオブジェクトに変更してください。希望の結果も追加してください。 –

+0

@NinaScholzさて、私は変更を加えました。 – alexchenco

+0

'colors.children'は1つの項目を含む配列です。これは別の配列です。これはおそらくあなたが望むものではなく、コードが期待しているものではありません。 – Arjan

答えて

1

まず、要求されたアイテムを(直接の子として)配置されている配列を返します検索方法。

function findDeep(arr, obj) { 
    return arr.map((item) => { 
     if (item.name === obj.name) { 
      return arr; 
     } else if (item.children) { 
      return findDeep(item.children, obj); 
     } else { 
      return undefined; 
     } 
    }).reduce((prev, cur) => { 
     return prev ? prev : cur; 
    }); 
} 

あなたがリストに項目を追加することを使用することができますが、それはまだ元の配列を変更します:

function appendDeep(arr, color, newColor) { 
    let found = findDeep(arr, color); 

    if (found) { 
     found.splice(found.indexOf(color) + 1, 0, newColor); 
    } 

    return arr; 
} 

あなたが元の配列を変更したくない場合は、物事をより複雑にし得ます。 pushspliceなどの標準の配列関数は元の配列を変更するためです。少なくとも私が知っているものではないので、あなたが本当に必要とする以上に多くのアイテムを複製したくないので、迅速な修正はありません。

blackを複製する必要はありませんが、それを含む配列を複製する必要があります(既存のオブジェクトを単に黒く再利用できます)。つまり、黄色のオブジェクトも複製する必要があります複製されたアレイ)および黄色が位置するアレイをクローニングする必要がある。しかし、同じ配列内にある白は変更されておらず、複製する必要もありません。私はそれを正しく行う方法を考え出していない。

+0

おかげでたくさんありました。私はこの一日を過ごしました。 'findDeep'は' undefined'を記録し続けました。すべてを動作させる部分は '.reduce((prev、cur)=> { return prev?prev:cur })'です。どのようにそれはその作品ではなく、それなしで動作しますか? ところで、「prev? prev:cur'と同じ 'prev ||カール? – alexchenco

+1

'map'は配列の各要素に関数を適用することによって配列を別の配列に変換します。 [reduce](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce)は、各要素に関数を適用することによって配列を単一の項目に変換します( 'また、前回の結果または中間の結果を関数に提供する。初期値を指定することもできます。この場合、私は初期値を必要としませんでした。そしてはい、 'prev || cur'は 'prevと同じ結果をもたらしますか? prev:cur'。どちらにも他のメリットがあるかどうかはわかりません。 – Arjan

+0

'prev? prev:cur'は、ESLint、haにおいて「不定期譲渡の使用」をスローする。助けてくれて、すべてを説明してくれてありがとう。 – alexchenco

2

あなたは再帰的な帰国されていませんmap内のfindDeepメソッド。条件分岐がマップ内から何も返さないため、再帰が機能するように戻します。結果としてundefinedという結果が得られます。 JSBin

+0

サンプルコードを教えてください。 – alexchenco

+0

私はこれを試しました: 'arr.map(item => { if(item.children)returnDeep(item.children、obj) })'でも、まだ 'undefined'を得ています。 – alexchenco

+0

作業用コードサンプルを含むJSBinを追加しました。今すぐチェックしてください。それは動作するはずです –

1

thisArgsArray#someとする提案です。

function appendDeep(object, search, insert) { 
 
    function iter(a) { 
 
     if (a.name === search.name) { 
 
      this.children.push(insert); 
 
      return true; 
 
     } 
 
     return Array.isArray(a.children) && a.children.some(iter, a); 
 
    } 
 

 
    object.children.some(iter, object); 
 
} 
 

 
var colors = { children: [{ name: 'white', }, { name: 'yellow', children: [{ name: 'black' }] }] }, 
 
    color = { name: 'black' }, 
 
    newColor = { name: 'brown' }; 
 

 
appendDeep(colors, color, newColor); 
 

 
document.write('<pre>' + JSON.stringify(colors, 0, 4) + '</pre>');