views:

74

answers:

2

Here is a peace of code:

void MyFunc(List<MyObj> objects)
{
  MyFunc1(objects);

  foreach( MyObj obj in objects.Where(obj1=>obj1.Good))
  {
    // Do Action With Good Object
  }
}

void MyFunc1(List<MyObj> objects)
{
  int iGoodCount = objects.Where(obj1=>obj1.Good).Count();
  BeHappy(iGoodCount);

  // do other stuff with 'objects' collection
}

Here we see that collection is analyzed twice and each time the value of 'Good' property is checked for each member: 1st time when calculating count of good objects, 2nd - when iterating through all good objects.

It is desirable to have that optimized, and here is a straightforward solution:

  • before call to MyFunc1 makecreate an additional temporary collection of good objects only (goodObjects, it can be IEnumerable);
  • get count of these objects and pass it as an additional parameter to MyFunc1;
  • in the 'MyFunc' method iterate not through 'objects.Where(...)' but through the 'goodObjects' collection.

Not too bad approach (as far as I see), but additional variable is required to be created in the 'MyFunc' method and additional parameter is required to be passed.

Question: is there any LinQ out-of-the-box functionality that allows any caching during 1st Where().Count(), remembering a processed collection and use it in the next iteration?

Any thoughts are welcome.

Thanks.

+2  A: 

No, LINQ queries are not optimized in this way (what you describe is similar to the way SQL Server reuses a query execution plan). LINQ does not (and, for practical purposes, cannot) know enough about your objects in order to optimize this way. As far as it knows, your collection has changed (or is entirely different) between the two calls.

You're obviously aware of the ability to persist your query into a new List<T>, but apart from that there's really nothing that I can recommend without knowing more about your class and where else MyFunc is used.

Adam Robinson
Anyway, thank you for you explanations.
Budda
A: 

As long as MyFunc1 doesn't need to modify the list by adding/removing objects, this will work.

void MyFunc(List<MyObj> objects)
{
  ILookup<bool, MyObj> objLookup = objects.ToLookup(obj1 => obj1.Good);
  MyFunc1(objLookup[true]);

  foreach(MyObj obj in objLookup[true])
  {
    //..
  }
}

void MyFunc1(IEnumerable<MyObj> objects)
{
  //..
}
David B