title: LINQ with Querying "Memory"
body: <p>Does <code>LINQ</code> have a way to "memorize" its previous query results <em>while querying</em>?</p>
  
  <p>Consider the following case:</p>
  
  <pre><code>public class Foo {
      public int Id { get; set; }
      public ICollection&lt;Bar&gt; Bars { get; set; }
  }
  
  public class Bar {
      public int Id { get; set; }
  }
  </code></pre>
  
  <p>Now, if two or more <code>Foo</code> have same collection of <code>Bar</code> (no matter what the order is), they are considered as <strong>similar</strong> <code>Foo</code>. </p>
  
  <p>Example:</p>
  
  <pre><code>foo1.Bars = new List&lt;Bar&gt;() { bar1, bar2 };
  foo2.Bars = new List&lt;Bar&gt;() { bar2, bar1 };
  foo3.Bars = new List&lt;Bar&gt;() { bar3, bar1, bar2 };
  </code></pre>
  
  <p>In the above case, <code>foo1</code> is <strong>similar</strong> to <code>foo2</code> but both <code>foo1</code> and <code>foo2</code> are <em>not</em> <strong>similar</strong> to<code>foo3</code></p>
  
  <p>Given that we have a <code>query</code> result consisting <code>IEnumerable</code> or <code>IOrderedEnumerable</code> of <code>Foo</code>. From the <code>query</code>, we are to find the first <code>N</code> <code>foo</code> which are <em>not</em> <strong>similar</strong>. </p>
  
  <p>This task seems to require a memory of the collection of <code>bars</code> which have been chosen before.</p>
  
  <p>With <em>partial</em> <code>LINQ</code> we could do it like this:</p>
  
  <pre><code>private bool areBarsSimilar(ICollection&lt;Bar&gt; bars1, ICollection&lt;Bar&gt; bars2) {
      return bars1.Count == bars2.Count &amp;&amp; //have the same amount of bars
          !bars1.Select(x =&gt; x.Id)
          .Except(bars2.Select(y =&gt; y.Id))
          .Any(); //and when excepted does not return any element mean similar bar
  }
  
  public void somewhereWithQueryResult(){
      .
      .
      List&lt;Foo&gt; topNFoos = new List&lt;Foo&gt;(); //this serves as a memory for the previous query
      int N = 50; //can be any number
      foreach (var q in query) { //query is IOrderedEnumerable or IEnumerable
          if (topNFoos.Count == 0 || !topNFoos.Any(foo =&gt; areBarsSimilar(foo.Bars, q.Bars)))
              topNFoos.Add(q);
          if (topNFoos.Count &gt;= N) //We have had enough Foo
              break;
      }
  }
  </code></pre>
  
  <p>The <code>topNFoos</code> <code>List</code> will serve as a memory of the previous query and we can skip the <code>Foo q</code> in the <code>foreach</code> loop which already have identical <code>Bars</code> with <code>Any</code> of the <code>Foo</code> in the <code>topNFoos</code>.</p>
  
  <p>My question is, is there any way to do that in <code>LINQ</code> (<em>fully</em> <code>LINQ</code>)?</p>
  
  <pre><code>var topNFoos = from q in query
                 //put something
                 select q;
  </code></pre>
  
  <p>If the "memory" required is from a particular query item <code>q</code> or a variable outside of the query, then we could use <code>let</code> variable to cache it: </p>
  
  <pre><code>int index = 0;
  var topNFoos = from q in query
                 let qc = index++ + q.Id //depends on q or variable outside like index, then it is OK
                 select q;
  </code></pre>
  
  <p>But if it must come from the <em>previous querying of the query itself</em> then things start to get more troublesome.</p>
  
  <p>Is there any way to do that?</p>
  
  <hr>
  
  <p><strong>Edit:</strong></p>
  
  <p><em>(I currently am <a href="https://github.com/ian5666987/linqmemorytest/blob/master/Program.cs" rel="nofollow">creating a test case</a> (github link) for the answers. Still figuring out how can I test all the answers fairly)</em></p>
  
  <p><em>(Most of the answers below are aimed to solve my particular question and are in themselves good (Rob's, spender's, and David B's answers which use <code>IEqualityComparer</code> are particularly awesome). Nevertheless, if there is anyone who can give answer to my more general question "does LINQ have a way to "memorize" its previous query results while querying", I would also be glad)</em></p>
  
  <p><em>(Apart from the significant difference in performance for the particular case I presented above when using fully/partial LINQ, one answer aiming to answer my general question about LINQ memory is Ivan Stoev's. Another one with good combination is Rob's. As to make myself clearer, I look for general and efficient solution, if there is any, using LINQ)</em></p>