2016-08-18 1 views
0

selectedTagsには最大3つのタグが含まれています。 vm.tags何千ものタグを含めることができますが、たぶん数百ものタグを比較する必要があります。このdouble forlopをlodashでリファクタリングする方法は?

3つのタグのIDがvm.tagsのタグのIDと一致する場合は、境界線をオンにする必要があります。 3つのボーダーもあります:border1border2border3です。

const tagsColorCheck =() => { 
    let name, selected, its_ticker; 
    let selectedTags = TagsFactory.retrieveTickerTags('onlyTags'); 

    if (selectedTags.length > 0) { 
     for (let i=0; i<vm.tags.length; i++) { 
      for (let j=0; j<selectedTags.length; j++) { 
       if (selectedTags[j].term_id == vm.tags[i].term_id) { 
        name  = 'border'+ (j + 1); 
        selected = 'selected'; 
        its_ticker = 'its_ticker'; 

        vm.tags[i][name]  = true; 
        vm.tags[i][selected] = true; 
        vm.tags[i][its_ticker] = selectedTags[j].its_ticker; 
       } 
      } 
     } 
    } 
}; 

は、これまでのところ、ここで私は、プロセス(_.each)に持っているものです。

const tagsColorCheck =() => { 
    let name, selected, its_ticker, vmTerm, term_1, term_2, term_3, ticker_1, ticker_2, ticker_3; 
    let selectedTags = TagsFactory.retrieveTickerTags('onlyTags'); 

    if (!_.isEmpty(selectedTags)) { 
     vmTerm = R.findIndex(R.propEq('term_id', selectedTags[0].term_id))(vm.tags); 
    } 

    if (selectedTags[0]) { term_1 = parseInt(selectedTags[0].term_id); ticker_1 = selectedTags[0].its_ticker; } 
    if (selectedTags[1]) { term_2 = parseInt(selectedTags[1].term_id); ticker_2 = selectedTags[1].its_ticker; } 
    if (selectedTags[2]) { term_3 = parseInt(selectedTags[2].term_id); ticker_3 = selectedTags[2].its_ticker; } 

    _.each(vm.tags, (tag) => { 
     if (tag.term_id === term_1) { 
      tag.selected = true; 
      tag.border1 = true; 
      tag.its_ticker = ticker_1; 
     } 

     if (tag.term_id === term_2) { 
      tag.selected = true; 
      tag.border2 = true; 
      tag.its_ticker = ticker_2; 
     } 

     if (tag.term_id === term_3) { 
      tag.selected = true; 
      tag.border3 = true; 
      tag.its_ticker = ticker_3; 
     } 
    }) 
}; 

そして、この(for of loop):

const tagsColorCheck =() => { 
    let name, selected, its_ticker, vmTerm, term_1, term_2, term_3, ticker_1, ticker_2, ticker_3; 
    let selectedTags = TagsFactory.retrieveTickerTags('onlyTags'); 

    const borderRizeTag = (tag) => { 
     if (tag.term_id === term_1) { 
      tag.selected = true; 
      tag.border1 = true; 
      tag.its_ticker = ticker_1; 
     } 

     if (tag.term_id === term_2) { 
      tag.selected = true; 
      tag.border2 = true; 
      tag.its_ticker = ticker_2; 
     } 

     if (tag.term_id === term_3) { 
      tag.selected = true; 
      tag.border3 = true; 
      tag.its_ticker = ticker_3; 
     } 
     return tag; 
    } 

    if (!_.isEmpty(selectedTags)) { 
     vmTerm = R.findIndex(R.propEq('term_id', selectedTags[0].term_id))(vm.tags); 
    } 

    if (selectedTags[0]) { term_1 = parseInt(selectedTags[0].term_id); ticker_1 = selectedTags[0].its_ticker; } 
    if (selectedTags[1]) { term_2 = parseInt(selectedTags[1].term_id); ticker_2 = selectedTags[1].its_ticker; } 
    if (selectedTags[2]) { term_3 = parseInt(selectedTags[2].term_id); ticker_3 = selectedTags[2].its_ticker; } 

    for (let tag of vm.tags) { 
     console.log(tag); 
     tag = borderRizeTag(tag); 
    } 

    console.log('vmTerm',vmTerm); 
}; 
+2

それは働いて、それが維持/理解しやすいですし、それがどの速く得ることはありません。だからなぜそれをlodash版に変換したいのですか? O.o - あなたのlodashスクリプトは、3つのタグに固定されていて、簡単に拡張できないように、やや混乱します。バニラ版にはこのすべてが無料で用意されています。 – Andreas

+0

実際の速度は気にしませんが、読みやすいです。機能的なプログラミング... forループは読みにくいですが、forループの二重はただの下痢です。 –

+0

@LeonGaban毎日機能的な言語でプログラムを作っていて、私が欲しいと思ってもループを書くことができない人として、あなたのdouble forループはあなたの他のバージョンよりもすぐに読みやすくなっていると伝えます。私は後で答えを書きますが、一般的な声明として「forループは読みにくい」という盲目的な信念を受け入れません。しばしばそうですが、あなたのケースではforループが勝ちます。 Andreas氏によると、あなたの他のバージョンは拡張性がなく、理由を説明するのが難しいです。 – Josh

答えて

3

ES6実行するためのフィドル:http://www.es6fiddle.net/is0prsq9/(ノート、テキスト全体をコピーし、ブラウザのコンソールまたはノードREPLの内側に貼り付け、その後、結果を見るためにtagsの値を調べ)

にですlodashではなく、あなたはES6のコンストラクトでそれを本当に必要としません。関連コード:あなたは関数型言語でこれを書いていた場合

const tagsColorCheck =() => { 

    let tags = TagsFactory.retrieveTickerTags('onlyTags') 

    sel.forEach((s,i) => 
    tags.filter(t => t.term_id === s.term_id).forEach(t => { 
     t['border' + (i+1)] = true 
     t.selected = true 
     t.its_ticker = s.its_ticker 
    }) 
) 

    return tags 
} 

、あなたがlist comprehensionへのアクセス権を持っているでしょうし、それは少しきれいになります。本質的に、これは(for every x in a and y in b)のかなり明確なケースです。リストの理解は必要なものですが、あなたはjavascript(mozilla has itですが、そのレルム以外では役に立たない)ではありません。

結果はやや機能的なアプローチですが、純粋なjavascriptでは決して機能しません。おそらく機能的なパラダイムの最も重要な利点はimmutable data structuresあなたの新しいリストを構成するでしょう。代わりに、ここでそれらの場所を変更するだけです。実際にはあまり機能しません。それでも、あなたが上記のようにリテラルなインクリメンタルなものへのアプローチを好むのであれば、私は自分のポストで行ったように、それは(遅くても間違いなくクリーンな)良いアプローチです。

+1

'name'を設定する行は' t ['border' +(i + 1)] = trueであると思います。また、オブジェクトの中のコンマも忘れないでください。 – 4castle

+0

@ 4castle - プロパティ名を訂正してくれてありがとう。 't => {'部分は新しいオブジェクトを生成していないので、配置するコンマはありません。これは単純に無名関数の関数本体です。 – Josh

+0

ああ私は今それを見る。そこには考えていませんでした。 – 4castle

1

は素晴らしい解決策を考え出しました! :Dは_lodashramdaの両方を使用しています。

以下のようにすぐにeachの方が速いので、R.equalsを使用してterm_idsと一致するかどうかを比較してください。次に、正しいtagオブジェクトのキーの値を設定します。

if (!_.isEmpty(selectedTags)) { 
    _.each(vm.tags, tag => { 

     _.each(selectedTags, (selectedTag, index) => { 
      let areTermIDsSame = R.equals; 

      if (areTermIDsSame(parseInt(selectedTag.term_id), parseInt(tag.term_id))) { 
       name  = 'border'+ (index + 1); 
       selected = 'selected'; 
       its_ticker = 'its_ticker'; 

       tag[name]  = true; 
       tag[selected] = true; 
       tag[its_ticker] = selectedTag.its_ticker; 
      } 
     }); 
    }) 
} 
+0

私はあなたがロダッシュの使用のポイントを逃したと思います。確かに、それは定型的な 'for'ループコードを削除しますが、そうでなければ同じ命令的スタイルのコードです。彼らの望みは機能コードなので、私はこれが改善されていると懐疑的だ。また、なぜ=== 'ではないのですか? – 4castle

+0

ああ、あるterm_idが文字列だったので、 '==='を使ってバグがありました。もう1つは数字でした。したがって、 'parseInt'を使って' R.equals'関数内の数字であることを確認してください。 –

+1

最も効率的であるためには、両方の番号を保存する必要があります。それ以外の場合は、繰り返しごとに解析する必要があります。 – 4castle

1

アイデアは単純です - すべてのタグのインデックスをterm_idで作成してください。選択したタグを繰り返します。タグがタグインデックス内のidによって見つかった場合は、そのオブジェクトに新しいプロパティを割り当てることによって変更します。

btw - lodashを使用したくない場合は、lodashが必要なのは_.keyBy()で、Array.prototype.reduceを使用すれば簡単に行うことができます。

/** mocked vm **/ 
 

 
const vm = { 
 
\t tags: [{ term_id: 1 }, { term_id: 2 }, { term_id: 3 }, { term_id: 4 }, { term_id: 5 }, { term_id: 6 }] 
 
} 
 

 
/** mocked TagsFactory **/ 
 

 
const TagsFactory = { 
 
\t retrieveTickerTags:() => [{ term_id: 1, its_ticker: 'ticker 1' }, { term_id: 4, its_ticker: 'ticker 4' }, { term_id: 5, its_ticker: 'ticker 5' }] 
 
}; 
 

 
const tagsColorCheck =() => { 
 
    const selectedTags = TagsFactory.retrieveTickerTags('onlyTags'); 
 

 
    if (selectedTags.length === 0) { // if selectedTags is empty exit 
 
    return; 
 
    } 
 

 
    const vmTagsIndex = _.keyBy(vm.tags, (tag) => tag.term_id); // create an index of tags by term_id 
 

 
    selectedTags.forEach(({ 
 
    term_id, its_ticker 
 
    }, index) => { // loop through selectd tags and retreive term_id and its_ticker from the current selected tag 
 
    const tag = vmTagsIndex[term_id]; // find the tag in the vmTagsIndex 
 

 
    if (!tag) { // if the id doesn't exist in vmTagsIndex exit 
 
     return; 
 
    } 
 

 
    Object.assign(tag, { // mutate the tag by assigining it an object with the available properties 
 
     selected: true, 
 
     [`border${index + 1}`]: true, 
 
     its_ticker 
 
    }); 
 
    }); 
 
}; 
 

 
tagsColorCheck(); 
 

 
console.log(vm.tags);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.15.0/lodash.min.js"></script>

関連する問題