views:

345

answers:

7

I'm getting started with C# 3.0 and LINQ, and I can't find a feature that to me is obvious, it's gotta be there.

I have an Enumerable, and I want to execute something for each instance of it. Something like...

string[] Names = ...; Names.each(s => Console.Writeline(s));

or

Names.each(s => GenHTMLOutput(s));
// (where GenHTMLOutput cannot for some reason receive the enumerable itself as a parameter)

Kind of like .Select() but for doing something instead of returning something.
I did try .Select(s=> { Console.WriteLine(s); return s; }), but it wasn't printing anything.

A: 

If you don't want to add your own extension method, try .All(). It takes a Predicate rather than an Action, so you'll need to return a boolean. But the semantics are still readable and it should perform a little better than converting to a list first, since you only iterate the collection once.

Joel Coehoorn
Downvoted: This will only process all items if the predicate continues to return "true". If you are executing a method which returns a boolean it could be very easy to accidentally introduce an error without realising it.
Peter Morris
+5  A: 

You are looking for the ever-elusive ForEach that currently only exists on the List generic collection. There are many discussions online about whether Microsoft should or should not add this as a LINQ method. Currently, you have to roll your own:

public static void ForEach<T>(this IEnumerable<T> value, Action<T> action)
{
  foreach (T item in value)
  {
    action(item);
  }
}

While the All() method provides similar abilities, it's use-case is for performing a predicate test on every item rather than an action. Of course, it can be persuaded to perform other tasks but this somewhat changes the semantics and would make it harder for others to interpret your code (i.e. is this use of All() for a predicate test or an action?).

Jeff Yates
I'd prefer it if it would be added. Including an overload that takes a Func<T,TResult> action and returns IEnumerable<TResult>. Even if that can be done with Select already.
peSHIr
You can certainly write one to do that, if that is your use-case.
Jeff Yates
Using All would be a bad idea - If any of those Func<T, bool>'s returned false, then execution would end.
David B
Yup, that's another great reason not to use it.
Jeff Yates
A: 

There is a ForEach method off of List. You could convert the Enumerable to List by calling the .ToList() method, and then call the ForEach method off of that.

Alternatively, I've heard of people defining their own ForEach method off of IEnumerable. This can be accomplished by essentially calling the ForEach method, but instead wrapping it in an extension method:

public static class IEnumerableExtensions
{
    public static IEnumerable<T> ForEach<T>(this IEnumerable<T> _this, Action<T> del)
    {
        List<T> list = _this.ToList();
        list.ForEach(del);
        return list;
    }
}
David Morton
That would force a complete sequence evaluation taking up memory for each element of the temporary List. I'd go with the extension method on IEnumerable<T> any time I can get away with to preserve the lazy evaluation properties as long as possible.
peSHIr
A: 

You cannot do this right away with LINQ and IEnumerable - you need to either implement your own extension method, or cast your enumeration to an array with LINQ and then call Array.ForEach():

Array.ForEach(MyCollection.ToArray(), x => x.YourMethod());

Please note that because of the way value types and structs work, if the collection is of a value type and you modify the elements of the collection this way, it will have no effect on the elements of the original collection.

DrJokepu
+3  A: 

Unfortunately there is no built-in way to do this in the current version of LINQ. The framework team neglected to add a .ForEach extension method. There's a good discussion about this going on right now on the following blog.

http://blogs.msdn.com/kirillosenkov/archive/2009/01/31/foreach.aspx

It's rather easy to add one though.

public static void ForEach<T>(this IEnumerable<T> enumerable, Action<T> action) {
  foreach ( var cur in enumerable ) {
    action(cur);
  }
}
JaredPar
A: 

Because LINQ is designed to be a query feature and not an update feature you will not find an extension which executes methods on IEnumerable<T> because that would allow you to execute a method (potentially with side effects). In this case you may as well just stick with

foreach(string name in Names)
Console.WriteLine(name);

Peter Morris
+1 - This is what I use.
David B
+3  A: 

A quick-and-easy way to get this is:

Names.ToList().ForEach(e => ...);
Jay Bazuzi
ToList() will evaluate every node in the IEnumerable, meaning that any lazy evaluation is done at that point. I'd rather leave this as late as possible by making my own extensions method.
Jeff Yates
Sorry guys, I chose the unpopular method.I understand the downside of losing lazy evaluation, but when i'm doing the ForEach on my list, I want it to happen NOW anyway, so there's not much advantage is lazying off anymore.
Daniel Magliola
The extension method IS better, and it's probably faster too, but this is "kind of" more standard for me, and short enough to type.Thanks Jay!
Daniel Magliola
There is a big problem with this. If you do ToList then all of the objects *must* exist in memory at once. If the source is a DB then at least using IEnumerable your objects may be unloaded once finished. Use ToList and you can run out of memory for large data sets!DON'T USE IT!
Peter Morris
Yes, there are plenty of drawbacks to this approach, but I'm amazed at how often they aren't a problem, and this simple approach works just fine. Fact is, most of my sequences are < 100 elements. (Maybe you're doing more interesting programming than I do.)
Jay Bazuzi
Peter, that's an EXCELLENT point. It doesn't really apply to my situation (and probably never will), but it's a good thing to keep in mind, it might become a problem in certain situations
Daniel Magliola
If the enumerable is already an array or list, using the Array or List ForEach is going to be considerably faster than a simple ForEach extension. Such a ForEach should check to see if it can index and use a for loop instead of foreach since apparently the compiler/runtime won't optimize.
MichaelGG