2017-02-12 18 views
1

を使用してオブジェクトの配列を含むオブジェクトの配列でJavaScriptオブジェクトを検索し、私はこのようになりますジャバスクリプトオブジェクトがあるとしましょう:ラムダ関数

var events = 
[ 
    { 
     name: "Foo event", 
     submissions: [ 
      { 
       id:"sub1", 
       name:"First submission" 
      }, 
      { 
       id:"sub2", 
       name:"Second submission" 
      } 
     ] 
    }, 
    { 
     name: "Bar event", 
     submissions: [ 
      { 
       id:"sub3", 
       name:"First submission in bar" 
      }, 
      { 
       id:"sub4", 
       name:"Second submission in bar" 
      } 
     ] 
    } 
] 

私は、例えばラムダ関数を書くことができるようにしたいですオブジェクト全体にID sub4考える

{ 
    id:"sub4", 
    name:"Second submission in bar" 
} 

を返します。何かのようなvar submission = events.magicLamba(...)私はArray.prototype.findを使用してみましたが、オブジェクトの配列からオブジェクトを選択する必要がある場合は、この場合は1つ以上の検索があります。

ありがとうございました。

編集:あなたの多くが指摘しているように、イベントは有効ではありませんでした。確かに配列だったので、元のデータのより簡単な例を書こうとしている間に書き留めておく必要があります。

+1

データオブジェクトが無効です – webdeb

+0

'events'は配列またはオブジェクトですか? –

+0

@ibrahimmahrirそれは配列なので、私はそれに応じて質問を編集しました –

答えて

0

私は私のために本当によく働く興味深い方法を発見しました。それはラムダ関数(すなわちsomeとfind)のみを使用し、かなり効率的です。

function findSubmissionUsingSome(events, submissionId){ 
    var submission; 
    events.some(event => { 
     submission = event.submissions.find(s => s.id === submissionId); //search for the submission in the current event, and store it in a variable 
     return submission; //returns truthy value if submission is found and exits some 
    }); 
    return submission; 
} 

あなたはテスト実行hereを見ることができ、私は(多分それは並列に動作します?)それはとてもうまく行って、なぜわからない、といくつかの明確化をしたいと思います。テストコードのために多くのRobMに感謝します。

+0

あなたは正しいです! 'some'の中の' find'はさらに優れています! –

+0

@FilippoVigani、実際にはこれはあなたがもともと受け入れた(そして今受け入れられていない)**私の答えよりも効率的ではありません** [このフィドルを見る](http://jsfiddle.net/rzzmnp2t/)**。デモコードには、1ミリ秒以下のES日付のタイミング精度があると考える必要があります。それは他の答えに逆らって説明するのに十分だった。この時点で、より大きなデータおよび/またはより大きなサンプルサイズが必要となります(このフィドルでは)。私は大きなサイズを持ってきたので、より多くのデバイス上で動作します。私のiPadでは、forループソリューションは一般的に300%〜400%高速です。ラインノートブックの上に40%から110%速く。 – RobM

+0

@FilippoVigani自分で比較して結果を報告してください。 – RobM

1

まあ、私はあなたのデータをコメントしているようには

events = { [] } // is not correct syntax.
多分それはevents = []

[OK]を、それが、少なくとも理にかなって配列、想像することができますする必要があり、無効であると思われます。

あなたfindSubmissionは、次のようになります。

function findSubmission(events, submissionId) { 
    var result; 
    events.forEach(function(event) { 
    event.submissions.forEach(function(submission) { 
     if (submission.id === submissionId) { 
     result = submission; 
     } 
    }) 
    }); 

    return result; 
} 

submission = findSubmission(events, "sub4"); 
+0

これはそれが見つかったとしても検索し続けませんか?そのため、パフォーマンスが= –

+0

trueの場合、これは単純なコードであり、最適化することができます – webdeb

2

まず、あなたの "イベント" は有効ではありません。それはちょうど外側の{ }を削除する必要があります場合は、配列のように見えます。

あなたの例では「id」を使用していたので、各提出IDは一意であると仮定します。

.foreach()を使用することはできますが、foreachから脱出する方法はありません。したがって、あなたが望むものを見つけても、すべての投稿を評価することになります。

したがって、私はforループを使用して、私が探していたものを見つけたら壊れてしまいます。これはより効率的です。私はいくつかのコンソールロギングを追加しました。あなたが望むものを見つけたら、データを評価し続けることはできません。

var events = [ 
     { 
      name: "Foo event", 
      submissions: [ 
       { id: "sub1", name: "First submission"}, 
       { id: "sub2", name: "Second submission"} 
      ] 
     }, 
     { 
      name: "Bar event", 
      submissions: [ 
       { id: "sub3", name: "First submission in bar" }, 
       { id: "sub4", name: "Second submission in bar"} 
      ] 
     } 
    ]; 

    function findSubmission(events, submissionId) { 
     var result = null; 
     for (var event of events) { 
      console.log("new event evaluated"); 
      for (var submission of event.submissions) { 
       console.log("evaluating submission: ",submission.id); 
       if (submission.id === submissionId) { 
        result = submission; 
        break; 
       } 
      } 
      if (result) break; 
     } 
     return result; 
    }; 

    var matchingSubmission = findSubmission(events, "sub3"); 
+0

これはこれまでのところ最も効率的な答えです。ラムダのみを使用して一致する投稿を見つける方法があることが期待されていましたMeierとwedebの回答は残念なことに、すべての単一の投稿を評価することなく)。 –

0

あなたは正しくfind()のみ提出アレイから提出を取得するためにあなたを助けることに気づきました。 map()で別のネストループを使用すると、ネストされたfind()呼び出しのすべての結果が返されます。最後のステップとして、結果配列から未定義の値をすべて削除する必要があります。

function findSubmissionUsingMap(events, submissionId) { 
    return events.map(function(event) { 
    return event.submissions.find(function(submission) { 
     return (submission.id === submissionId) 
    }) 
    }).filter(function(x) {return x}); 
}; 
+0

フィードバックいただきありがとうございます。もちろん、いくつかの方法があります。私は配列メソッドを使って答えを出そうとしました。 – Meier

+1

.map()は非常に便利ですが、結果をマップする必要がないので、ここでは適切ではありません。ループを行うために単純に使用しています。これは実行可能で、.for()または.foreach()。このアプローチの結果、処理を停止できなくなり、余分なフィルタリングを行う必要があるなど、効率の低いコードや不要なアクションが発生します。 – RobM

+0

@RobMあなたのフィドルを使って私は自分の質問に自分自身の答えを試してみました。それは不思議に仕上がっていますが、なぜそれが起こるのか分かりません。何か不足していますか?あなたがそれを調べるなら、私はそれをたくさん感謝します。 –

1

あなたがこのように欲しいものを達成するためにsomeを使用することができます。

var events = [{name: "Foo event",submissions: [{id:"sub1",name:"First submission"},{id:"sub2",name:"Second submission"}]},{name: "Bar event",submissions: [{id:"sub3",name:"First submission in bar"},{id:"sub4",name:"Second submission in bar"}]}] 
 

 
function find(arr, id) { 
 
    var res;       // uninitialized thus the result will be undefined if nothing is found 
 
    arr.some(      // unlike forEach some will stop after the first match (after the first callback call that returned true) 
 
    o => o.submissions.some(
 
     o => o.id == id && (res = o) // return true if o.id == id, false otherwise (and if o.id == id then assign o to result) 
 
    ) 
 
); 
 
    return res; 
 
} 
 

 
console.log(find(events, "sub2")); 
 
console.log(find(events, "sub4")); 
 
console.log(find(events, "sub499999"));

+0

私はこれが大好きです。すべてのイベントを通過してすべての投稿を渡すオーバーヘッドがありますが(すべての投稿を一度に渡す)、とてもきれいに見えます。 –

+0

@FilippoVigani送信オブジェクトはコピーされません。しかし、それらへの参照は 'reduce'の結果配列に格納されます。したがって、 'reduce'の結果配列は数値の配列として最適化されています! –

+0

これはjavascriptオブジェクトの美しさです! –