25
\$\begingroup\$

Since I don't know how LINQ works under the hood, I can't decide what version is best to use in term of rapidity of execution. I've done some testing with my testing data (Point Cloud) but I can't see a clear difference between the 2. The only thing I know is that the real life data will be a larger Point Cloud so my guess is that the LINQ would be faster but this is only if LINQ doesn't do a for each under the hood. If it's the case, the 2 functions would be the same. What is your advice?

By the way, cylindre is a 3D cylinder and I want to know which point are inside.

Version 1 without LINQ

for (int i = 0; i < fpc.Vertices.Length; i++)
{
    if (cylindre.IsPointInside(fpc.Vertices[i]))
        listPoint.Add(fpc.Vertices[i]);
}

Version 2, with LINQ

var insidePoint =
    from pt1 in fpc.Vertices
    where cylindre.IsPointInside(pt1)
    select pt1;

    foreach (Point3D pt2 in insidePoint)
    {
        listPoint.Add(pt2);
    }
\$\endgroup\$
  • 4
    \$\begingroup\$ This might help: programmers.stackexchange.com/questions/80084/… \$\endgroup\$ – ANeves Aug 1 '12 at 12:44
  • \$\begingroup\$ @ANeves Interesting article. I don't think my question in premature since this is in the requirement and very important because it will be done like 500 times a day by each user. And the only reason I don't have real data is that the final product isn't ready but I know for sure that it will be larger so optimization at this moment is very important. I'm also considering other way of improving the function but the difference between linq and the foreach was something that interest me. \$\endgroup\$ – Jean-François Côté Aug 1 '12 at 13:06
  • 3
    \$\begingroup\$ Have you squeezed every bit of performance algorithmically? Which data structures and algorithms you use matters. Some highly optimized libraries for .Net will perform some computations faster. Also, perhaps it is possible to use PLINQ and utilize multiple cores at once? I would measure that too. \$\endgroup\$ – Leonid Aug 1 '12 at 15:49
  • \$\begingroup\$ Thanks for the info. In fact, we have created a very small subset to run the foreach now it runs super fast, with LINQ and the foreach. \$\endgroup\$ – Jean-François Côté Aug 1 '12 at 17:09
  • 1
    \$\begingroup\$ In the LINQ version, you might consider using AddRange() instead of foreach. It won't increase performance, but it will make your code more readable. Also, using Where() directly will be shorter than from/where/select. \$\endgroup\$ – svick Aug 2 '12 at 9:06
5
\$\begingroup\$

Under the hood LINQ will iterate over the collection, just as foreach will. The difference between LINQ and foreach is that LINQ will defer execution until the iteration begins.

Performance wise take a look at this blog post.

\$\endgroup\$
  • 1
    \$\begingroup\$ Just a note about that link. The link is dealing with deleting elements from a list. It uses a for loop, then contrasts that with a double foreach loop and a LINQ/foreach combo. Not really a fair comparison. \$\endgroup\$ – pstrjds Aug 9 '12 at 13:40
7
\$\begingroup\$

As has been said, the for loop will most likely be more performant, but you can still clean the code up a bit more:

for (int i = 0; i < fpc.Vertices.Length; i++)
{
    if (cylindre.IsPointInside(fpc.Vertices[i]))
        listPoint.Add(fpc.Vertices[i]);
}

Can become:

foreach (var vertice in fpc.Vertices)
{
    if (cylindre.IsPointInside(vertice))
        listPoint.Add(vertice);
}

EDIT: As per the performance question. This code will run in LINQPad. I found that the foreach version performs a few milliseconds better than the for loop.

var elements = Enumerable.Range(0, 4000000).Select(x => true).ToArray();


var sw = new Stopwatch();
var result = new List<bool>();
int trueCount = 0;
sw.Start();
for(int i=0; i < elements.Length; ++i)
{
    if (elements[i])
    {
        ++trueCount;
        result.Add(elements[i]);
    }
}

sw.Stop();
sw.ElapsedMilliseconds.Dump();

sw.Reset();
trueCount = 0;
result = new List<bool>();
sw.Start();
foreach(var element in elements)
{
    if (element)
    {
        ++trueCount;
        result.Add(element);
    }
}
sw.Stop();
sw.ElapsedMilliseconds.Dump();

EDIT2 - Regarding the link that seems to indicate such drastically poor performance in a foreach loop

The link (http://www.schnieds.com/2009/03/linq-vs-foreach-vs-for-loop-performance.html) is dealing with removing elements from a list. In the case that you have a generic list, removing elements via a for loop is not normally the best approach. A better approach is to use the RemoveAll method. RemoveAll will remove all elements matching the predicate and then consolidate the list as opposed to RemoveAt which will require moving all elements above the removed element. For performance comparison of the removal please see the below code (once again, this can be run in LINQPad). In my testing the RemoveAll ran roughly 250x faster.

var elements = Enumerable.Range(0, 100000).Select(x => x % 2 == 0).ToArray();

var sw = new Stopwatch();
var source = new List<bool>(elements);
sw.Start();
for(int i=0; i < source.Count; ++i)
{
    if (!source[i])
    {
        source.RemoveAt(i);
        --i;
    }
}

sw.Stop();
sw.ElapsedMilliseconds.Dump();
int count = source.Count;

sw.Reset();
source = new List<bool>(elements);

sw.Start();
source.RemoveAll((bool x) => {return x;});
sw.Stop();
sw.ElapsedMilliseconds.Dump();
\$\endgroup\$
  • \$\begingroup\$ Replacing the for loop by a foreach will decrease the performance, as stated in Xharze's link schnieds.com/2009/03/… \$\endgroup\$ – Goldorak84 Aug 9 '12 at 13:09
  • 2
    \$\begingroup\$ @Goldorak84 - If you look at the code sample for that link, you will see that in both the foreach and LINQ case the code walked the list twice as compared to the for case that only walked the list once. That link was dealing with removing items from a list, and could have been written without a loop using RemoveAll which would be faster than even the for loop. \$\endgroup\$ – pstrjds Aug 9 '12 at 13:29
  • \$\begingroup\$ @pstrjds - I'm sorry, you are totally right. I adapted the code sample to apply the foreach and linq list removing mechanism on the for loop. The difference between the for and the foreach is barely noticeable. \$\endgroup\$ – Goldorak84 Aug 9 '12 at 14:51
1
\$\begingroup\$

Update:

If you're targeting .net 4 or later, you could use:

Parallel.ForEach()

or

RemoveAll().Parallel();

They should be faster than other methods.

\$\endgroup\$
  • 1
    \$\begingroup\$ List<T>.RemoveAll() returns an int representing the number of elements removed from the list. Did you mean List<T>.AsParallel()? \$\endgroup\$ – Mathieu Guindon Apr 15 '14 at 22:13
0
\$\begingroup\$

I don't think it will run faster on LINQ. The function cylindre.IsPointInside would still have to be called on each item of Vertices.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.