Linq Select into New Object Performance

I am new to Linq, using C#. I got a big surprise when I executed the following:

    var scores = objects.Select( i => new { object = i, 
        score1 = i.algorithm1(), 
        score2 = i.algorithm2(), 
        score3 = i.algorithm3() } );

    double avg2 = scores.Average( i => i.score2); // algorithm1() is called for every object
    double cutoff2 = avg2 + scores.Select( i => i.score2).StdDev(); // algorithm1() is called for every object

    double avg3 = scores.Average( i => i.score3); // algorithm1() is called for every object
    double cutoff3 = avg3 + scores.Select( i => i.score3).StdDev(); // algorithm1() is called for every object

    foreach( var s in scores.Where( i => i.score2 > cutoff2 | i.score3 > cutoff3 ).OrderBy( i => i.score1 )) // algorithm1() is called for every object
    {
        Debug.Log(String.Format ("{0} {1} {2} {3}\n", s.object, s.score1, s.score2/avg2, s.score3/avg3));
    }

The attributes in my new objects store the function calls rather than the values. Each time I tried to access an attribute, the original function is called. I assume this is a huge waste of time? How can I avoid this?

Jon Skeet
people
quotationmark

Yes, you've discovered that LINQ uses deferred execution. This is a normal part of LINQ, and very handy indeed for building up queries without actually executing anything until you need to - which in turn is great for pipelines of multiple operations over potentially huge data sources which can be streamed.

For more details about how LINQ to Objects works internally, you might want to read my Edulinq blog series - it's basically a reimplementation of the whole of LINQ to Objects, one method at a time. Hopefully by the end of that you'll have a much clearer idea of what to expect.

If you want to materialize the query, you just need to call ToList or ToArray to build an in-memory copy of the results:

var scores = objects.Select( i => new { object = i, 
    score1 = i.algorithm1(), 
    score2 = i.algorithm2(), 
    score3 = i.algorithm3() } ).ToList();

people

See more on this question at Stackoverflow