views:

83

answers:

2
IQueryable<SomeType> collection = GetCollection();
foreach (var c in collection)
{
    //do some complex checking that can't be embedded in a query
    //based on results from prev line we want to discard the 'c' object
}

//here I only want the results of collection - the discarded objects

So with that simple code what is the best way to get the results. Should I created a List just before the foreach and insert the objects I want to keep, or is there some other way that would be better to do this type of thing.

I know there are other posts on similar topics but I just don't feel I'm getting what I need out of them.

Edit I tried this

 var collection = GetCollection().Where(s =>
 {
      if (s.property == 1)
      {
           int num= Number(s);
           double avg = Avg(s.x);
           if (num > avg)
               return true;
           else
               return false;
      }
      else return false;
 });

I tried this but was given "A lambda expression with a statement body cannot be converted to an expression tree" on compile. Did I not do something right?

+2  A: 
//do some complex checking that can't be embedded in a query

I don't get it. You can pass a delegate which can point to a very complex function (Turing-complete) that checks whether you should discard it or not:

var result = GetCollection().AsEnumerable().Where(c => { 
  // ...
  // process "c"
  // return true if you want it in the collection
             });

If you want, you can refactor it in another function:

var result = GetCollection.Where(FunctionThatChecksToDiscardOrNot);
Mehrdad Afshari
I didn't realize you could throw brackets in there and then do function calls and everything. I'm not sure if it will work this way in this circumstance since in those brackets I will have to make a call to another dataContext, but its worth a shot.
jamone
@jamone: If you want to pass it to a `DataContext` you may need to use `delegate(ItemType c) { return doIWant(c); }` to force it to call the `Where(Func<T,bool>)` overload as you may want the function to be processed on the client side (as opposed to calling `Where(Expression<Func<T,bool>>` for translation to SQL and getting executed on the database server, which doesn't work on general functions). -- Or you could add a `.AsEnumerable()` before `.Where` and force `Where` to execute on the client regardless of the argument being a lambda or a delegate.
Mehrdad Afshari
The .AsEnumerable() made it work
jamone
@jamone: Yes, it should work with that in any case. One possible optimization (when you are working with LINQ to SQL) is to perform a two step `Where`. The first step will be a simple filtering that can be done on the server to reduce the amount of records that reach the client and the second step will process the complex part of the function: `GetCollection().Where(simpleLambdaToRunOnServer).AsEnumerable().Where(complexLambdaToRunOnClient)`
Mehrdad Afshari
Ok that will be handy. Thanks a bunch.
jamone
A: 

If you wrap it into another method, you can use yield return and then iterate over the returned collection, like so:

public IEnumerable<SomeType> FindResults(IQueryable<SomeType> collection) {

    foreach (var c in collection)
    {
        if (doComplicatedQuery(c)) {
            yield return c;
        }
    }
}

// elsewhere
foreach (var goodItem in FindResults(GetCollection())) {
   // do stuff.
}
Ryan Brunner