LINQ Aggregate vs. nested foreach - linq

I am trying to achieve:
foreach (ScheduleItem s in ScheduleItems)
{
foreach (IScheduleModule m in s.ScheduleModules)
{
yield return m;
}
}
using LINQ aggregate and I do not understand why
return ScheduleItems.Aggregate(new Collection<IScheduleModule>(), (x, o) => x.Union(o.ScheduleModules) as Collection<IScheduleModule>);
returns null.
I have no issue using the nested foreach but my instinct was to use aggregate and I don't understand why it doesn't produce the same result.
Are there other approaches? What is best in terms of readability and performance?

You should be using SelectMany for this:
ScheduleItems.SelectMany(s => s.ScheduleModules)
That exactly matches your initial nested foreach loop. It's also equivalent to this query expression:
from s in ScheduleItems
from m in s.ScheduleModules
select m
(although that will use a slightly different form of SelectMany).
As for why Aggregate isn't working: you're calling Union which returns an IEnumerable<T>, but then using as to try to convert it to Collection<T>. The result of Union won't be a Collection<T>, hence the result of the as operator is null.

Have you tried using SelectMany? Based on your question, that sounds like what you are looking for.
var results = ScheduleItems.SelectMany(si => si.ScheduleModules);

Related

refactor IF...ELSE into Nested foreach to LINQ

I am having troubles on finding a way to refactor my nested foreach code into a Linq, mostly because it includes an IF-Else clause into it.
Below is a simplified version of my code. How do I include the IF..Else into a linq statement??
I appreciate your suggestions.
List<hierarchy> PredomHierarchy;
List<hierarchy> RecesesHierarchy;
foreach x in PredomHierarchy{
foreach y in RecesesHierarchy{
if(x.name = y.name){
Dosomething(x.name, y.name);
} else {
DosomethingElse(x.name, y.name);
}
}
}
You can not (and should not) do for each in LINQ. See https://blogs.msdn.com/b/ericlippert/archive/2009/05/18/foreach-vs-foreach.aspx for an explanation why.
However, what you are doing is a cross product (or carthesian product). You can formulate it like this:
from x in PredomHierarchy
from y in RecesesHierarchy
select new {x,y}
and then just iterate the result collection:
.ToList().ForEach(item => {if (item.x.name == item.y.name) DoSomething(x,y); else DoSomethingElse(x,y);});
At that point, you are probably better off with the nested for each calls, though.

Longish LINQ query breakes SQLite-parser - simplify?

I'm programming a search for a SQLite-database using C# and LINQ.
The idea of the search is, that you can provide one or more keywords, any of which must be contained in any of several column-entries for that row to be added to the results.
The implementation consists of several linq-queries which are all put together by union. More keywords and columns that have to be considered result in a more complicated query that way. This can lead to SQL-code, which is to long for the SQLite-parser.
Here is some sample code to illustrate:
IQueryable<Reference> query = null;
if (searchAuthor)
foreach (string w in words)
{
string word = w;
var result = from r in _dbConnection.GetTable<Reference>()
where r.ReferenceAuthor.Any(a => a.Person.LastName.Contains(word) || a.Person.FirstName.Contains(word))
orderby r.Title
select r;
query = query == null ? result : query.Union(result);
}
if (searchTitle)
foreach (string word in words)
{
var result = from r in _dbConnection.GetTable<Reference>()
where r.Title.Contains(word)
orderby r.Title
select r;
query = query == null ? result : query.Union(result);
}
//...
Is there a way to structure the query in a way that results in more compact SQL?
I tried to force the creation of smaller SQL-statments by calling GetEnumerator() on the query after every loop. But apparently Union() doesn't operate on data, but on the underlying LINQ/SQL statement, so I was generating to long statements regardless.
The only solution I can think of right now, is to really gather the data after every "sub-query" and doing a union on the actual data and not in the statement. Any ideas?
For something like that, you might want to use a PredicateBuilder, as shown in the chosen answer to this question.

Nhibernate linq. The where extension method does not add the where clause to the SQL command, why?

I want to add the where clause to a linq statement, but it doesn't behave as i would expected it to.
When i use this code:
IQueryable<Employee> EmpQuery = from e in Session.Query<Employee>() where e.Surname == "Test" select e;
EmpQuery.ToList();
or i use this code:
IQueryable<Employee> EmpQuery = (from e in Session.Query<Employee>() select e).Where(e => e.Surname == "Test");
EmpQuery.ToList();
The where clause is included in the SQL command, but when i try it this way:
IQueryable<Employee> EmpQuery = from e in Session.Query<Employee>() select e;
EmpQuery.Where(e => e.Surname == "Test");
The where clause is not included in the SQL command. Why is this? Is there another way to dynamically add criteria to a Nhibernate Linq query?
You're not using the return value of Where. LINQ is designed around functional concepts - calling Where doesn't modify the existing query, it returns a new query which applies the filter. The existing query remains as it was - which means you can reuse it for (say) a different filter.
Note that your current query expression (from x in y select x, effectively) is pretty pointless. I would suggest simply writing:
var query = Session.Query<Employee>().Where(e => e.Surname == "Test");
Just to clarify on Jon's remark, your implementation would be fine with the following tweak:
IQueryable<Employee> modifiedQuery = EmpQuery.Where(e => e.Surname == "Test");
Then just invoke the appropriate enumerator (ToList, ToArray, foreach) on modifiedQuery. And I wouldn't say that it create a complete new query, but instead creates a query which wraps around the original (kind of along the lines of the adapter pattern). Granted, your example doesn't need the additions, but this is how you would add additional criteria onto an existing LINQ expression, and that is what your question actually asked.

Help converting foreach to Linq

this is a homework question.
I am doing diffs on our domain model and I've set it up so that I can iterate a list of operations that check for certian differences within the domain. I pass in the differencing function and the before and after states of the object graph to produce a result in the DiffContext - which is used later to set up a payload for calling another service. But I've made some changes and need help with the Linq syntax
So, I have the following code ...
public static IEnumerable<DiffContext> GetFirstDifference<T>(IEnumerable<Func<T, T, DiffContext>> diffOperations, T beforeState, T afterState)
{
return from op in diffOperations
let diff = op(beforeState, afterState)
where diff.FoundDifference
select diff;
}
Which I modified to use Func<T, T, IEnumerable<DiffContext>> instead of the previous Func<T, T, DiffContext> - because now my diff operations can return multiple differences. Like so..
public static IEnumerable<DiffContext> GetFirstDifference<T>(IEnumerable<Func<T, T, IEnumerable<DiffContext>>> diffOperations, T beforeState, T afterState)
{
foreach (var op in diffOperations)
{
foreach (var diff in op(beforeState, afterState))
{
yield return diff;
}
}
}
But now I have this nested foreach and I'd like some help converting it to the Linq equivalent. Can you help?
Thanks Jon Skeet. I now have the following instead of the nested foreach:
return from op in diffOperations
from diff in op(beforeState, afterState)
where diff.FoundDifference
select diff;
Yup - you want two "from" clauses, basically - that performs a flatten operation. This uses the SelectMany LINQ operator.
Given that this is homework, I'm reluctant to post the full code - but I will say it's a three-line LINQ query (using the natural line breaking). Think about what you want "from" each collection...
Just add comments if that's not enough of a hint.

Multiple Defered WHERE clause expressions in LINQ to SQL

Maybe a simple question, I'm trying to get a result from a table where the Name column contains all of an array of search terms. I'm creating a query and looping through my search strings, each time assigning the query = query.Where(...);. It appears that only the last term is being used, I supposed because I am attempting to restrict the same field each time. If I call .ToArray().AsQueryable() with each iteration I can get the cumlative restrinction behavior I'm looking for, but it there an easy way to do this using defered operators only?
Thanks!
If you're doing something like:
foreach (int foo in myFooArray)
{
query = query.where(x => x.foo == foo);
}
...then it will only use the last one since each where criteria will contain a reference to the 'foo' loop variable.
If this is what you're doing, change it to:
foreach (int foo in myFooArray)
{
int localFoo = foo;
query = query.where(x => x.foo == localFoo);
}
...and everything should be fine again.
If this is not what is happening, please provide a code sample of what you're doing...

Resources