I am trying to find the fastest way to apply some simple calculation on values within an IEnumerable<IPoint>.
IPoint being an interface with two parameters decimal Quantity and decimal Price.
I also have a Point class that implements the interface such as :
public class Point : IPoint
{
public decimal Quantity { get; set; }
public decimal Price { get; set; }
public Point(decimal q, decimal p)
{
Quantity = q;
Price = p;
}
}
I want to transform my IEnumerable<IPoint> such that the result would be an IEnumerable<IPoint> where quantity = price * quantity and price = 1 / price
I compared the results of using IEnumerable.Select and a simple foreach iteration over the elements of the IEnumerable.
I randomly generated a IEnumerable<IPoint> Initial and transform it with the following:
IEnumerable<IPoint> WithSelect = new List<Point>();
IEnumerable<IPoint> WithForeach = new List<Point>();
//With Select
var watch = System.Diagnostics.Stopwatch.StartNew();
WithSelect = Initial.Select(p => new Point(p.Price * p.Quantity, 1 / p.Price));
watch.Stop();
var elapsed1Ms = watch.ElapsedMilliseconds;
var ListTmp = new List<Point>();
//With foreach
watch.Restart();
foreach(var p in Initial)
{
ListTmp.Add(new Point(p.Price * p.Quantity, 1 / p.Price));
}
WithForeach = ListTmp;
watch.Stop();
var elapsed2Ms = watch.ElapsedMilliseconds;
The performance are:
foreach: ~460 ms for 1M points and ~3800ms for 10M pointsSelect: 0ms for 1M and 10M points....
If I do a WithSelect = WithSelect.ToList() to have a more "usable" type (i.e. going from System.Linq.Enumerable.SelectEnumerableIterator<IPoint, Point> to System.Collections.Generic.List<IPoint>) the execution time goes up to ~3900 ms (i.e. slightly more than the for each).
I would say great, let's go for the Select without transforming the result, but I wonder if the execution time (0ms, no matter the size of the Enumerable) is not hiding something. Does it mean that the actual calculation is only made when I access the values ? Would it also mean that if I access several time the values I'll start stacking up the calculation time ? Or is it just a very good Linq optimization that I should not worry about ?
In case the Select is hiding some extra later calculation times, is there an alternative to the two I tried that I should look for ?