C#: Any benefit of List T .ForEach(...) over plain foreach loop?
One key difference is with the .ForEach method you can modify the underlying collection. With the foreach syntax you'll get an exception if you do that. Here's an example of that (not exactly the best looking but it works):
static void Main(string[] args) {
try {
List<string> stuff = new List<string>();
int newStuff = 0;
for (int i = 0; i < 10; i++)
stuff.Add(".");
Console.WriteLine("Doing ForEach()");
stuff.ForEach(delegate(string s) {
Console.Write(s);
if (++newStuff < 10)
stuff.Add("+"); // This will work fine and you will continue to loop though it.
});
Console.WriteLine();
Console.WriteLine("Doing foreach() { }");
newStuff = 0;
foreach (string s in stuff) {
Console.Write(s);
if (++newStuff < 10)
stuff.Add("*"); // This will cause an exception.
}
Console.WriteLine();
}
catch {
Console.WriteLine();
Console.WriteLine("Error!");
}
Console.ReadLine();
}
Performance IEnumerable T .ToList().ForEach() over loop
In the first example, you will
- Create a list by enumerating the source
- Enumerate through the new list and call
Console.WriteLine
for each element.
In the second example, you will
- Enumerate through the source and call
Console.WriteLine
for each element.
There are two performance penalities to the first over the second:
- The creation of the new
List
object - The double enumeration: over the original source, and then the list
Use a foreach loop within a foreach loop in a linq query
I believe this foreach
loop will achieve your goal, if I've understood the problem.
It will loop over any element of items
that is a (or is derived from) SubItem
. It will then select all SomeObject.SomeString
strings and add them to the SomeList
.
foreach (var subItem in items.OfType<SubItem>()) {
subItem.SomeList.AddRange(subItem.SomeObject.Select(o => o.SomeString));
}
This is a compilation of suggestions from Panagiotis Kanavos, juharr, and Aluan Haddad.
Is it more efficient to perform a LINQ in a foreach statement?
@Jeremy Lakeman provided the right answer in comments.
The type of the variable listA
in:
var listA = someList.TakeWhile(predicate);
is IEnumerable<T>
, T being the type of an individual element of your collection someList
. This is clearly shown by the signature of the TakeWhile
method:
public static System.Collections.Generic.IEnumerable<TSource> TakeWhile<TSource> (this System.Collections.Generic.IEnumerable<TSource> source, Func<TSource,int,bool> predicate);
as can be seen at the TakeWhile
documentation page.
Declaring a variable of type IEnumerable<T>
doesn't enumerate it.
To enumerate an IEnumerable
, you have to do it explicitly, by enumerating it if a foreach
loop for instance, or by using it to produce a new materialized collection, such as a List
, Dictionary
, etc... by calling methods such .ToList()
or ToDictionary()
, etc...
This is explicitly stated in the (for instance) ToList
documentation:
The
ToList<TSource>(IEnumerable<TSource>)
method forces immediate
query evaluation and returns aList<T>
that contains the query
results. You can append this method to your query in order to obtain a
cached copy of the query results.ToArray
has similar behavior but
returns an array instead of aList<T>
.
So in both your code examples, the IEnumerable
you construct will be enumerated only once in the foreach
loop.
Also: even if you had materialized your collection before enumerating it:
var listA = someList
.TakeWhile(predicate)
.ToList(); // Notice the .ToList() call that forces the enumeration.
foreach(var item in listA)
{
/// perform code here
}
It would still be an O(n) operation, not an O(n^2).
If you take N elements from your someList
collection, you will enumerate them once with the .ToList()
call, and once in the foreach
loop, for a total of 2 x N, not N^2.
Performance difference for control structures 'for' and 'foreach' in C#
Well, it partly depends on the exact type of list
. It will also depend on the exact CLR you're using.
Whether it's in any way significant or not will depend on whether you're doing any real work in the loop. In almost all cases, the difference to performance won't be significant, but the difference to readability favours the foreach
loop.
I'd personally use LINQ to avoid the "if" too:
foreach (var item in list.Where(condition))
{
}
EDIT: For those of you who are claiming that iterating over a List<T>
with foreach
produces the same code as the for
loop, here's evidence that it doesn't:
static void IterateOverList(List<object> list)
{
foreach (object o in list)
{
Console.WriteLine(o);
}
}
Produces IL of:
.method private hidebysig static void IterateOverList(class [mscorlib]System.Collections.Generic.List`1<object> list) cil managed
{
// Code size 49 (0x31)
.maxstack 1
.locals init (object V_0,
valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<object> V_1)
IL_0000: ldarg.0
IL_0001: callvirt instance valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<!0> class [mscorlib]System.Collections.Generic.List`1<object>::GetEnumerator()
IL_0006: stloc.1
.try
{
IL_0007: br.s IL_0017
IL_0009: ldloca.s V_1
IL_000b: call instance !0 valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<object>::get_Current()
IL_0010: stloc.0
IL_0011: ldloc.0
IL_0012: call void [mscorlib]System.Console::WriteLine(object)
IL_0017: ldloca.s V_1
IL_0019: call instance bool valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<object>::MoveNext()
IL_001e: brtrue.s IL_0009
IL_0020: leave.s IL_0030
} // end .try
finally
{
IL_0022: ldloca.s V_1
IL_0024: constrained. valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<object>
IL_002a: callvirt instance void [mscorlib]System.IDisposable::Dispose()
IL_002f: endfinally
} // end handler
IL_0030: ret
} // end of method Test::IterateOverList
The compiler treats arrays differently, converting a foreach
loop basically to a for
loop, but not List<T>
. Here's the equivalent code for an array:
static void IterateOverArray(object[] array)
{
foreach (object o in array)
{
Console.WriteLine(o);
}
}
// Compiles into...
.method private hidebysig static void IterateOverArray(object[] 'array') cil managed
{
// Code size 27 (0x1b)
.maxstack 2
.locals init (object V_0,
object[] V_1,
int32 V_2)
IL_0000: ldarg.0
IL_0001: stloc.1
IL_0002: ldc.i4.0
IL_0003: stloc.2
IL_0004: br.s IL_0014
IL_0006: ldloc.1
IL_0007: ldloc.2
IL_0008: ldelem.ref
IL_0009: stloc.0
IL_000a: ldloc.0
IL_000b: call void [mscorlib]System.Console::WriteLine(object)
IL_0010: ldloc.2
IL_0011: ldc.i4.1
IL_0012: add
IL_0013: stloc.2
IL_0014: ldloc.2
IL_0015: ldloc.1
IL_0016: ldlen
IL_0017: conv.i4
IL_0018: blt.s IL_0006
IL_001a: ret
} // end of method Test::IterateOverArray
Interestingly, I can't find this documented in the C# 3 spec anywhere...
Find() vs. enumeration on lists
They are not equivalent in performance. The Find() method requires a method (in this case delegate) invocation for every item in the list. Method invocation is not free and is relatively expensive as compared to an inline comparison. The foreach version requires no extra method invocation per object.
That being said, I wouldn't pick one or the other based on performance until I actually profiled my code and found this to be a problem. I haven't yet found the overhead of this scenario to every be a "hot path" problem for code I've written and I use this pattern a lot with Find and other similar methods.
When to use which for?
Option A only really makes sense for sequences that implement indexing and will only be performant for those that have O(1)
lookup time. Generally, I would use the foreach
and variants unless you have special logic.
Also note, that "special logic" like for (int i = 1; i < list.Count; i++)
can be implemented with Linq extension methods: foreach(var item in sequence.Skip(1))
.
So, generally prefer B over A.
As to C: This can be confusing for other developers if they aren't used to the functional style.
As to D: This will depend on a lot of factors. I guess for simple calculations, you don't want to do this - you will only really benefit from parallelization if the loop body takes a while to compute.
System.ArgumentOutOfRangeException why is it showing? And why does the list number stop printing?
As @tkausl already mentioned, ForEach passes you the value, not the index, it is not recommended to use List.ForEach
actually, but if you still want to use it, you can do something like this:
number.ForEach(c => { Console.WriteLine(c); });
You can simply use a foreach
like this:
foreach (var c in number)
{
Console.WriteLine(c);
}
You can find the discussion here: foreach vs someList.ForEach(){}
Related Topics
Parsing JSON Object with Variable Properties into Strongly Typed Object
How to Convert an Enum to a List in C#
Install a .Net Windows Service Without Installutil.Exe
Collection<T> Versus List<T> What Should You Use on Your Interfaces
Visual Studio "Could Not Copy" .... During Build
Mapping Object to Dictionary and Vice Versa
Creating Instance of Type Without Default Constructor in C# Using Reflection
Dropdownlist in MVC 4 with Razor
Differencebetween Using Idisposable VS a Destructor in C#
Restsharp JSON Parameter Posting
How to Use Mvvmlight Simpleioc
Reducing Memory Usage of .Net Applications
How to Play a Sound in C#, .Net
How to Use the Ternary Operator Inside an Interpolated String