3

From the below 2 ways to enumerate a collection, should one be preferred over the other OR are both the same in terms of performance (i.e. since ToList() conversion is involved in the second approach)

foreach(SomeType st in Collection)
{
   //Do something
}


Collection.OfType<SomeType>.ToList().ForEach()

Is there any other way (except using relection)?

EDIT

How about this scenario?

class SomeType : IMyType
{
}

class OtherType : IMyType
{
}

class SomeCollection<T> : IList<T>, ICollection<T>, IEnumerable<T>, IList, ICollection, IEnumerable
{
}

Considering MyTypes is a property in a class with type SomeCollection<IMyType> the below 2 approaches same?

foreach(IMyType mt in MyTypes) 
{   
  if(IMyType is SomeType)
  return; 
}

OR

if(MyTypes.OfType<SomeType>.Any())
    return;
stackoverflowuser
  • 20,984
  • 28
  • 65
  • 89
  • Which one should be used really depends on what you are trying to do. – Oded Dec 29 '10 at 19:37
  • Depending on the collection (and if it extends CollectionBase), you can just reference the IList interface and the ForEach method and iterate over it (no need to convert to a list first). – Brad Christie Dec 29 '10 at 19:42
  • @Brad Christie IList does not support ForEach, List does. – Tim Lloyd Dec 29 '10 at 19:43
  • And on the type of the collection. For example, OfType() filters your collection based on type. If you already know that all the objects in the collection are of type SomeType, then there's no reason to call OfType(). Also, if the collection implements ICollection, then the list constructor that's invoked in ToList() will behave a little more efficiently than it otherwise would. – phoog Dec 29 '10 at 19:44
  • @chibacity, you're right. Thought I was in the IList docs. The list class is the one that implements ForEach. Touché, I stand corrected. – Brad Christie Dec 29 '10 at 19:46

6 Answers6

3

Sure, with indexable collections you could use a classic for loop:

for( int i = 0; i < collection.Count; i++ )
{
    collection[i] ... // do something with the item
}

You could also directly access the IEnumerator object (which foreach is syntactic sugar for):

using( IEnumerator<YourType> e = collection.GetEnumerator() )
{
    while( e.MoveNext() )
    {
        // do something with the item
        e.Current ...
    }
}

All of the different approaches for enumerating a collection are useful in some specific cases - but it is very contextual as to which pattern to use where.

For instance, using the IEnumerator object directly is useful where you want fine grained control over exactly how and when to increment and access the iterator. Many LINQ operators internally use IEnumerator to optimize their implementation.

A reasonable rule of thumb is: that when you are visiting items in order to produce side effects you should use for or foreach, when you are transforming (projecting) one sequence into another you should use LINQ (Select, Where, etc...). Using LINQ emphasizes the result while hiding the mechanism, whereas loops emphasizes the mechanism.

LBushkin
  • 121,016
  • 31
  • 208
  • 258
3

Of those you mentioned, the first is preferred. The second one will do a lot more, involving converting to a list and checking for type just to do a foreach in the end anyway.

There are certainly other ways to iterate, but they depend on the collection. For IList implementations and arrays you can use a normal for loop and index the items using myitem[i].

But there are no reasons not to use foreach since it works for all collections and is AFAIK always the most optimal choise in terms of performance. By optimal I mean in terms of algorithm complexity/big-o

EDIT in response to your question edit In general, you should use the enumeration scheme that provides the best readability (without seriously impacting performance obviosly). In your example, where you want to see if your list has any elements of a particular type then I would go with the LINQ route (collection.OfType...). It clearly expresses intent and it's almost possible to read the text in english and get the meaning: "In my collection, get elements of type X and tell me if there are any."

Isak Savo
  • 32,569
  • 10
  • 58
  • 90
  • 1
    +1. See also http://blogs.msdn.com/b/ericlippert/archive/2009/05/18/foreach-vs-foreach.aspx – TrueWill Dec 29 '10 at 19:48
  • You don't need to say "For IList implementations and arrays" because arrays implement IList. Apparently `for` is marginally faster than `foreach` in some cases, but not enough to make a difference. – phoog Dec 29 '10 at 19:48
  • @phoog If my memory serves me well, arrays support IList in a rather unusual way and from experience treating arrays as ILists is several orders of magnitude slower. Maybe they have fixed the issue... – Tim Lloyd Dec 29 '10 at 19:54
  • @phoog: I suspected that but wasn't sure so I put "...and arrays" in there to be explicit. Thanks for clairifying – Isak Savo Dec 29 '10 at 20:00
  • @chibacity: I wasn't aware of significant performance differences with the array implementation of IList; thanks for the warning. Also, I wanted to add this link to my earlier comment about for vs foreach performance: http://stackoverflow.com/q/365615/385844 – phoog Dec 29 '10 at 20:07
  • @phoog Just ran a benchmark in .Net 4.0. Accessing the array indexer via IList is about 7 times slower than directly. This is much improved over .Net 2.0 where it was a serious problem. – Tim Lloyd Dec 29 '10 at 20:23
1

There is Parallel.ForEach:

http://msdn.microsoft.com/en-us/library/dd460720.aspx

Peter T. LaComb Jr.
  • 2,875
  • 2
  • 28
  • 44
0

Obviously, not converting the collection will be faster than converting it.

John Saunders
  • 157,405
  • 24
  • 229
  • 388
0

I would prefer the first approach because you don't lose the underlying enumerator as you would if you convert to a list. For most collections there's not much difference, but if it's a large collection or one that's being calculated by yielding results, then it could be important.

MarkXA
  • 3,841
  • 16
  • 19
0

For some types of collections (like List(Of T)) enumerating via classic foreach is much faster. This is because foreach construct in C# does not use IEnumerator and IEnumerable directly.

It calls GetEnumerator() method then calls MoveNext() and Current on object returned. Since List returns ListEnumerator structure which methods are faster when called directly otherwise calling via IEnumerator interface.

STO
  • 9,252
  • 6
  • 28
  • 32