473,978 Members | 28,103 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

foreach or List.ForEach

Which is the better way to go and why?

//trivial example
List<string> strings = GetStrings();
foreach (string s in strings)
{
// some operation;
}

strings.ForEach (
delegate(string s)
{
// some operation
}
);
Jan 19 '06
27 79988
Willy Denoyette [MVP] wrote:
Just add two lines, and watch the result...
..
stopwatch.Start ();
// Put the list into an array for performance
string[] sa = new string[list.Count]; <----
list.CopyTo(sa, 0); <----
Yes, but I think that counts as cheating :)
Also, try to run the first two tests only, and watch the results....


I don't see any difference there. What difference are you seeing?

Jon

Jan 20 '06 #11
Patrik wrote:
will you blog on this so I can link it from mine?


http://msmvps.com/blogs/jon.skeet/ar...reachperf.aspx

Jon

Jan 20 '06 #12

"Jon Skeet [C# MVP]" <sk***@pobox.co m> wrote in message
news:11******** *************@g 43g2000cwa.goog legroups.com...
| Willy Denoyette [MVP] wrote:
|
| > Just add two lines, and watch the result...
| > ..
| > stopwatch.Start ();
| > // Put the list into an array for performance
| > string[] sa = new string[list.Count]; <----
| > list.CopyTo(sa, 0); <----
|
| Yes, but I think that counts as cheating :)
|

Yes, a little bit ;-), but isn't that (don't keep allocating enumerators)
what ForEach is doing also?

| > Also, try to run the first two tests only, and watch the results....
|
| I don't see any difference there. What difference are you seeing?

First version: 00:00:10.590905 9 (correct? True)
Second version: 00:00:04.496689 1 (correct? True)
Third version: 00:00:04.494429 5 (correct? True)

First version: 00:00:11.449503 4 (correct? True)
Second version: 00:00:08.977291 5 (correct? True)

Willy.
Jan 20 '06 #13

"Tripper" <Tr*****@discus sions.microsoft .com> wrote in message
news:8E******** *************** ***********@mic rosoft.com...
Which is the better way to go and why?

//trivial example
List<string> strings = GetStrings();
foreach (string s in strings)
{
// some operation;
}

strings.ForEach (
delegate(string s)
{
// some operation
}
);


foreach is the most readable which is way more important than any trivial
speed difference.

If you're into speed you should try:

int len - strings.Length;
for(int i = 0; i < len;++i)
sim += strings[i].Length;

I have read stuff saying that this should be fastest because it is
realtively easy to JIT compile it into entirely in-line code.


Jan 20 '06 #14
For a string (ar any other simple) array, yes you may be right...

However, if this was a linked-list implementation, either of the foreach /
ForEach methods is likely to outperform it due to not having to start at the
beginning each time (assuming it doesn't internally keep a cursor for
reference via the indexers).

Another issue with both the enumerator syntax and the List<T>.ForEach syntax
is that they force the caller down a particular route; this may be fine if
the varialbe is private to method, but if the variable is a *parameter* it
seems (to me at least) to use IEnumerable<T> to a: satisfy the "least
required" paradigm, and b: give the caller the most flexibility (i.e. they
can give me a list, an array, a collection, a linked-list, or whatever). And
yes, I could write an overload with the improved performance, but then I
increase my maintenance overhead.

If desired usage dictates, I might just about stretch to providing a "params
T[]" overload (which in turn calls the IEnumerable<T> version, maintaining a
single functional code-base), but I don't really want to write (and
maintain) 3 versions of the code (one for T[] using indexers, one for
List<T> using ForEach and one for IEnumerable<T> using foreach).

For me, then, foreach is still my *default* way to go (although I will make
exceptions under consideration); although not always the *absolute* best, it
is suitably performant (i.e. in the same league) without imposing any
restrictions, plus it avoids careless errors due to incorrect use (i.e.
using an indexer with a linked list).

Marc

Jan 20 '06 #15
And yes - I know you weren't advicating usage on a linked list;

My point is that there is a category of developer who could read this ad
think "ah, indexer usage is best" and then use it constantly. Regardless of
whether they actually have an array or just something with indexer access.
And it isn't as simple as that.

I wasn't disagreeing in principle, though.

Marc
Jan 20 '06 #16
Willy Denoyette [MVP] wrote:
| Yes, but I think that counts as cheating :)

Yes, a little bit ;-), but isn't that (don't keep allocating enumerators)
what ForEach is doing also?
Well, there's a big difference between "copy this potentially huge
array" and "allocate a single enumerator".
| > Also, try to run the first two tests only, and watch the results....
|
| I don't see any difference there. What difference are you seeing?

First version: 00:00:10.590905 9 (correct? True)
Second version: 00:00:04.496689 1 (correct? True)
Third version: 00:00:04.494429 5 (correct? True)

First version: 00:00:11.449503 4 (correct? True)
Second version: 00:00:08.977291 5 (correct? True)


Odd. How are you compiling and running? Do you get the same difference
if you use the new benchmark as linked to from my blog entry?
(http://msmvps.com/blogs/jon.skeet/ar...reachperf.aspx)

Jon

Jan 20 '06 #17

"Jon Skeet [C# MVP]" <sk***@pobox.co m> wrote in message
news:11******** *************@g 44g2000cwa.goog legroups.com...
| Willy Denoyette [MVP] wrote:
| > | Yes, but I think that counts as cheating :)
| >
| > Yes, a little bit ;-), but isn't that (don't keep allocating
enumerators)
| > what ForEach is doing also?
|
| Well, there's a big difference between "copy this potentially huge
| array" and "allocate a single enumerator".
|

Not sure what you mean by that, ForEach doesn't allocate enumerators, while
foreach on the list allocates an enumerator and calls Dispose once per
iteration. 'foreach' on an array (as I did) doesn't allocate an enumerator,
it simply uses a pointer calls get_Length to get the length of the string
and advances the pointer.

| > | > Also, try to run the first two tests only, and watch the results....
| > |
| > | I don't see any difference there. What difference are you seeing?
| >
| > First version: 00:00:10.590905 9 (correct? True)
| > Second version: 00:00:04.496689 1 (correct? True)
| > Third version: 00:00:04.494429 5 (correct? True)
| >
| > First version: 00:00:11.449503 4 (correct? True)
| > Second version: 00:00:08.977291 5 (correct? True)
|
| Odd. How are you compiling and running? Do you get the same difference
| if you use the new benchmark as linked to from my blog entry?
| (http://msmvps.com/blogs/jon.skeet/ar...reachperf.aspx)
|
| Jon
|

Compiling and running from the command line with /o and /o-. Using XP SP2
and 2.0.50727.42.

There is definitely something wrong with this (First version and Second
version), the problem doesn't occur when Third follows First. More trying to
profile the "second" version alone crashes the profilers (VS2005 as well as
special profiler using the HW CPU and memory controller perfcounters). I'm
actually looking into this to see what's happening.

The new version doesn't have any of these issues, that is, they show
consistent timing and no profiler crashes !?
Here are my results running on the same box as above results.

Compiled from the cmd line with /o
Test parameters: Size=100000; Iterations=1000 0
Test 00:00:11.021892 3: LanguageForEach
Test 00:00:04.541090 5: NewDelegateEach Time
Test 00:00:04.513824 8: CachedDelegate
Test 00:00:13.687767 0: LanguageForEach WithCopy1
Test 00:00:01.678258 2: LanguageForEach WithCopy2

Same with /o-
Test parameters: Size=100000; Iterations=1000 0
Test 00:00:11.665539 3: LanguageForEach
Test 00:00:04.582094 0: NewDelegateEach Time
Test 00:00:04.545938 6: CachedDelegate
Test 00:00:14.416172 1: LanguageForEach WithCopy1
Test 00:00:02.268416 2: LanguageForEach WithCopy2

First two tests only.
Test parameters: Size=100000; Iterations=1000 0
Test 00:00:11.048661 9: LanguageForEach
Test 00:00:04.538974 6: NewDelegateEach Time

Notice the huge difference for the last test when o is turned off! The fun
of micro-benchmarks.
Willy.
Jan 20 '06 #18
Willy Denoyette [MVP] wrote:
| Well, there's a big difference between "copy this potentially huge
| array" and "allocate a single enumerator".

Not sure what you mean by that, ForEach doesn't allocate enumerators, while
foreach on the list allocates an enumerator and calls Dispose once per
iteration.
Sorry, yes, I misread which kind of ForEach you meant. The difference
between copying it to an array and calling ForEach is that ForEach
doesn't need the extra allocation. In other words, although using array
copy / foreach is faster than using ForEach (if you copy it once and
then iterate multiple times, at least), it's clearly more expensive in
terms of memory.

<snip>
| Odd. How are you compiling and running? Do you get the same difference
| if you use the new benchmark as linked to from my blog entry?
| (http://msmvps.com/blogs/jon.skeet/ar...reachperf.aspx)

Compiling and running from the command line with /o and /o-. Using XP SP2
and 2.0.50727.42.
Interesting. I've been running with .NET 1.1. I'll try it later with
..NET 2.0 and see if that makes a difference.
There is definitely something wrong with this (First version and Second
version), the problem doesn't occur when Third follows First. More trying to
profile the "second" version alone crashes the profilers (VS2005 as well as
special profiler using the HW CPU and memory controller perfcounters). I'm
actually looking into this to see what's happening.
Goodo :)
The new version doesn't have any of these issues, that is, they show
consistent timing and no profiler crashes !?
Well, there's significantly less codependence in the new version, so
I'm not entirely surprised. It's a more realistic test in various ways.

<snip>
Notice the huge difference for the last test when o is turned off! The fun
of micro-benchmarks.


Absolutely.

Jon

Jan 20 '06 #19

"Jon Skeet [C# MVP]" <sk***@pobox.co m> wrote in message
news:11******** **************@ z14g2000cwz.goo glegroups.com.. .
| Willy Denoyette [MVP] wrote:
| > | Well, there's a big difference between "copy this potentially huge
| > | array" and "allocate a single enumerator".
| >
| > Not sure what you mean by that, ForEach doesn't allocate enumerators,
while
| > foreach on the list allocates an enumerator and calls Dispose once per
| > iteration.
|
| Sorry, yes, I misread which kind of ForEach you meant. The difference
| between copying it to an array and calling ForEach is that ForEach
| doesn't need the extra allocation. In other words, although using array
| copy / foreach is faster than using ForEach (if you copy it once and
| then iterate multiple times, at least), it's clearly more expensive in
| terms of memory.
|

True, there is the memory cost. isn't making "informed and sound design
tradeoffs" the beauty of software design?

| <snip>
|
| > | Odd. How are you compiling and running? Do you get the same difference
| > | if you use the new benchmark as linked to from my blog entry?
| > |
(http://msmvps.com/blogs/jon.skeet/ar...reachperf.aspx)
| >
| > Compiling and running from the command line with /o and /o-. Using XP
SP2
| > and 2.0.50727.42.
|
| Interesting. I've been running with .NET 1.1. I'll try it later with
| .NET 2.0 and see if that makes a difference.
|

Hmmmm... generics and anon delegates on v1.1???
| > There is definitely something wrong with this (First version and Second
| > version), the problem doesn't occur when Third follows First. More
trying to
| > profile the "second" version alone crashes the profilers (VS2005 as well
as
| > special profiler using the HW CPU and memory controller perfcounters).
I'm
| > actually looking into this to see what's happening.
|
| Goodo :)
|
| > The new version doesn't have any of these issues, that is, they show
| > consistent timing and no profiler crashes !?
|
| Well, there's significantly less codependence in the new version, so
| I'm not entirely surprised. It's a more realistic test in various ways.
|

Yep, but there is more than the performance drop. The same test runs
correctly on Intel P4 and Mobile HW, but shows this pattern on 32/64 bit AMD
and Intel.

Willy.

Jan 20 '06 #20

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

5
7975
by: Jeffrey Silverman | last post by:
Hi, all. I have a linked list. I need an algorithm to create a tree structure from that list. Basically, I want to turn this: $list = array( array( 'id' => 'A', 'parent_id' => null, 'value' => 'aaa') , array( 'id' => 'B', 'parent_id' => 'A', 'value' => 'bbb') , array( 'id' => 'C', 'parent_id' => 'B', 'value' => 'ccc') , array( 'id' => 'D', 'parent_id' => 'A', 'value' => 'ddd')
32
4224
by: James Curran | last post by:
I'd like to make the following proposal for a new feature for the C# language. I have no connection with the C# team at Microsoft. I'm posting it here to gather input to refine it, in an "open Source" manner, and in an attempt to build a ground-swell of support to convince the folks at Microsoft to add it. Proposal: "first:" "last:" sections in a "foreach" block The problem: The foreach statement allows iterating over all the...
13
2025
by: cody | last post by:
foreach does implicitly cast every object in the collection to the specified taget type without warning. Without generics this behaviour had the advantage of less typing for us since casting was neccessary in nearly every collection. But with generics I consider this feature of foreach as dangerous. Casting is now almost always unwanted. interface IFoo{} class Foo:IFoo{} class FooBar:IFoo{}
9
2818
by: garyusenet | last post by:
I'm a bit confused about the differences of these two commands (what is the right word for commands here?) when used to enumerate the contents of an array. The below example uses both foreach and for to enumerate the contents of the array. Also as well as explaining the differences could you explain why the foreach messagebox isn't working below. Many TIA.
7
4059
by: =?Utf-8?B?RXZhbiBSZXlub2xkcw==?= | last post by:
I am a C++ programmer and have been learning C#. I have constructed a List<> and I want to iterate over it, altering each string in the list. In C++, I'd just create an iterator and walk the list, so I was looking for something similar in C#. I looked at foreach, List.ForEach, and IEnumerator. The problem is that all of them seem to return readonly pointers to the items in the List. Therefore I can't alter the list. So I'm using a for...
3
2207
by: =?Utf-8?B?YW1pcg==?= | last post by:
Hi, I have a Generic Object that has a private List field item. I populate the List in a different function I use a FOREACH LOOP with a FindAll function to get all items that have a certain match for data in the list and do something to it. The problem is that it repeats for all data items in the list and not
4
2598
by: Peter Morris | last post by:
I am not sure what you are asking. You seem to be asking how to implement a plain IEnumerable on a composite structure, but then your example shows a flat structure using "yield". Your subject makes me infer that you think foreach is enirely useless for composite structures. I will address the subject text, because that makes the most sense to me :-) Take the following class public class MyTreeNode : IEnumerable<MyTreeNode> {
0
10356
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However, people are often confused as to whether an ONU can Work As a Router. In this blog post, we’ll explore What is ONU, What Is Router, ONU & Router’s main usage, and What is the difference between ONU and Router. Let’s take a closer look ! Part I. Meaning of...
0
11826
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers, it seems that the internal comparison operator "<=>" tries to promote arguments from unsigned to signed. This is as boiled down as I can make it. Here is my compilation command: g++-12 -std=c++20 -Wnarrowing bit_field.cpp Here is the code in...
0
11416
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven tapestry of website design and digital marketing. It's not merely about having a website; it's about crafting an immersive digital experience that captivates audiences and drives business growth. The Art of Business Website Design Your website is...
0
10087
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing, and deployment—without human intervention. Imagine an AI that can take a project description, break it down, write the code, debug it, and then launch it, all on its own.... Now, this would greatly impact the work of software developers. The idea...
1
8464
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new presenter, Adolph Dupré who will be discussing some powerful techniques for using class modules. He will explain when you may want to use classes instead of User Defined Types (UDT). For example, to manage the data in unbound forms. Adolph will...
0
7618
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and then checking html paragraph one by one. At the time of converting from word file to html my equations which are in the word document file was convert into image. Globals.ThisAddIn.Application.ActiveDocument.Select();...
0
6421
by: TSSRALBI | last post by:
Hello I'm a network technician in training and I need your help. I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs. The last exercise I practiced was to create a LAN-to-LAN VPN between two Pfsense firewalls, by using IPSEC protocols. I succeeded, with both firewalls in the same network. But I'm wondering if it's possible to do the same thing, with 2 Pfsense firewalls...
0
6561
by: adsilva | last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
1
5161
by: 6302768590 | last post by:
Hai team i want code for transfer the data from one system to another through IP address by using C# our system has to for every 5mins then we have to update the data what the data is updated we have to send another system

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.