I'm working with LINQ to objects and have a function where in some cases I need to modify the underlying collection before calling Aggregate(...)
and then return it to its original state before the funciton returns the results of Aggregate(...)
. My current code looks something like this:
bool collectionModified = false;
if(collectionNeedsModification)
{
modifyCollection();
collectionModified = true;
}
var aggregationResult = from a in
(from b in collection
where b.SatisfysCondition)
.Aggregate(aggregationFunction)
select a.NeededValue;
if(collectionModified)
modifyCollection();
return aggregationResult;
However, as written, if I modify the collection, I will get the wrong result because I'm putting the collection back in its original state before aggregationResult
is enumerated and LINQ results are lazy-evaluated. My current solution is to use .ToArray()
on my LINQ query like this:
var aggregationResult = (from a in
(from b in collection
where b.SatisfysCondition)
.Aggregate(aggregationFunction)
select a.NeededValue).ToArray();
The size of the resulting array will always be small (< 100 items) so memory / processing time is not a concern. Is this the best way to handle my problem, or is there a better way to force the evaluation of a LINQ query?
ToArray might do an additional allocation and copy operation such that the buffer will be sized exactly to the number of elements. In order to confirm this the following benchmark is used. The results confirm that ToList is in most cases 10% - 15% faster.
LINQ ToList() Method In LINQ, the ToList operator takes the element from the given source, and it returns a new List. So, in this case, input would be converted to type List.
This extension method converts collections (IEnumerables) to List instances. It is fast and easy-to-remember. It returns a List instance with the appropriate elements.
Just to check I understand you - you basically want to iterate through all of the results, just to force any side effects to take place?
Side effects are generally a bad idea precisely because things are harder to understand with this kind of logic. Having said that, the easiest way to do it and force full evaluation is probably to just iterate through it:
foreach (var result in aggregationResult)
{
// Deliberately empty; simply forcing evaluation of the sequence.
}
Alternatively you could use LastOrDefault() to avoid all the copying involved in ToArray(). Count() will be okay so long as the result doesn't implement IList<T>
(which involves a short-cut).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With