locked
Linq selecting first item for speed RRS feed

  • Question

  • I can do a linq query and get .First() or Take(1), but I want to optimize the speed and stop the search after it's found 1 match.

    var result = from a in myList where a.ID = 123 select a;

    If it hits ID =123, I want it to stop since there will only be 1 item with ID 123.

    Take(1) and First() will still go through all the items in myList


    dan

    Friday, May 10, 2013 5:58 PM

Answers

  • "Take(1) and First() will still go through all the items in myList"

    No, they won't.  Neither of these methods will result in iterating any more of the source collection than is needed.

    This is easily proven:

    var list = new List<int>() { 1, 0 };
    
    int i = list.First(n => 2 / n > 0);


    If `First` iterates the entire sequence then this will throw a divided by zero exception.  If it stops when it finds the first match (which is the first item) then it won't crash and will instead return 1.  

    You can apply the same test with `Take(1)` if you want:

    var list = new List<int>() { 1, 0 };
    
    foreach (var i in list.Where(n => 2 / n > 0).Take(1))
        Console.WriteLine(i);

    This will also just write out "1" rather than crashing.  If "Take" iterated the entire sequence anyway then it would just crash.

    • Edited by servy42 Friday, May 10, 2013 6:25 PM
    • Proposed as answer by Wizend Friday, May 10, 2013 6:50 PM
    • Marked as answer by danparker276 Friday, May 10, 2013 6:58 PM
    Friday, May 10, 2013 6:19 PM

All replies

  • "Take(1) and First() will still go through all the items in myList"

    No, they won't.  Neither of these methods will result in iterating any more of the source collection than is needed.

    This is easily proven:

    var list = new List<int>() { 1, 0 };
    
    int i = list.First(n => 2 / n > 0);


    If `First` iterates the entire sequence then this will throw a divided by zero exception.  If it stops when it finds the first match (which is the first item) then it won't crash and will instead return 1.  

    You can apply the same test with `Take(1)` if you want:

    var list = new List<int>() { 1, 0 };
    
    foreach (var i in list.Where(n => 2 / n > 0).Take(1))
        Console.WriteLine(i);

    This will also just write out "1" rather than crashing.  If "Take" iterated the entire sequence anyway then it would just crash.

    • Edited by servy42 Friday, May 10, 2013 6:25 PM
    • Proposed as answer by Wizend Friday, May 10, 2013 6:50 PM
    • Marked as answer by danparker276 Friday, May 10, 2013 6:58 PM
    Friday, May 10, 2013 6:19 PM
  • Ah, I thought it would do what's in parens first.  Thanks

    dan

    Friday, May 10, 2013 6:37 PM