Linq question on foreach

  • Thread starter Thread starter CSharper
  • Start date Start date
C

CSharper

I have following code

using (StreamWriter writer = new StreamWriter("log.log"))
{
foreach (string arg in args)
{
writer.WriteLine(arg);
}
}

I remember some in the group said, Linq will replace (most of it)
foreach. How can achive what i am doing above with linq?

Thanks,
 
CSharper said:
using (StreamWriter writer = new StreamWriter("log.log"))
{
foreach (string arg in args)
{
writer.WriteLine(arg);
}
}

I remember some in the group said, Linq will replace (most of it)
foreach. How can achive what i am doing above with linq?

It's not exactly that "linq will replace foreach". Whoever said that,
probably meant that LINQ would let you avoid foreach in those cases in which
the loop is used to "filter" a collection. For instance, if your code above
where instead like this:

foreach (string arg in args)
{
if (arg.EndsWith("z") && arg.Length==7)
writer.WriteLine(arg);
}

then you could replace it with this:

var r = from arg in args
where arg.EndsWith("z") && arg.Length==7
select arg;
foreach (var r1 in r) writer.WriteLine(r1);

Note that we did NOT replace the foreach. What we replaced is the list of
conditions within the foreach. This is not particularly interesting in a
simple case like the one above, but it can become more significant when you
have a couple of nested loops searching two collections (can be replaced by
a "join" in al Linq query), or selecting various properties of the objects
in those collections and then building new objects out of them, which could
all be done in the Linq query and would make the code simpler and more
readable. Linq can also sort and group your data, which is annoying to code
manually into a loop or set of loops.
 
What's wrong with the code you posted?

There are certainly ways to get the Enumerable class (which implements  
LINQ methods) to do what you want, and you could probably even contrive a 
LINQ expression that calls the class to achieve the end result.

But, you'd basically be taking what's an imperative operation and  
representing it functionally, which doesn't seem like a great way to write  
the code.  The code you posted seems to do a good job of expressing what  
it is exactly you want to do, so what advantage would there be to  
rewriting it using LINQ syntax?

Pete

Thanks both. Yes I am very comfortable with the code I wrote and I was
just curious to see how would one will approach this problem with Linq
thats all.
 
Maybe it was something like this?

using (var writer = new StreamWriter("log.log"))
args.ToList().ForEach(s => writer.Write(s));
 
Maybe it was something like this?

   using (var writer = new StreamWriter("log.log"))
    args.ToList().ForEach(s => writer.Write(s));

Technically, ForEach() is not LINQ-related, and on the whole this is
obviously an inferior solution (as there's no need to convert an
IEnumerable to List just to iterate over it).

The way I see it, the lack of Enumerable.ForEach() in LINQ is an
indication that the preferred way of doing some action for every
element of an IEnumerable is still the plain foreach statement. LINQ
is really for manupulation on the sequences themselves - filtering,
sorting, grouping, projecting etc - not actions on their individual
elements.
 
Technically, ForEach() is not LINQ-related,

I know.
and on the whole this is
obviously an inferior solution (as there's no need to convert an
IEnumerable to List just to iterate over it).
<<

On account that you don't know me I will ignore the fact that you are
telling me something so obvious :-)

The way I see it, the lack of Enumerable.ForEach() in LINQ is an
indication that the preferred way of doing some action for every
element of an IEnumerable is still the plain foreach statement.
<<

I disagree with this. IEnumerable.ForEach would merely do the same as a
foreach anyway, so there would be absolutely no difference; it's merely a
matter of taste. I think the lack of IEnumerable.ForEach is an annoyance.

names.ForEach(Console.WriteLine);

vs

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

It's a minor difference, but why stop me from doing it when they are
equivalent?

LINQ
is really for manupulation on the sequences themselves - filtering,
sorting, grouping, projecting etc - not actions on their individual
elements.
<<

Well, I must say I do agree, but I still think IEnumerable.ForEach would be
nice.

But back onto the original topic. I know that List.ForEach is not LINQ but
I think some people still struggle to differentiate between lamdas and LINQ.
I suspected the original person may have meant this but incorrectly called
it "LINQ". The answer could be right but the question wrong, which is why I
suggested it. I can't think of any way LINQ could be used to improve the
original code, so I thought I'd try to throw some more light on the original
advice instead.
 
CSharper,
I have following code

using (StreamWriter writer = new StreamWriter("log.log"))
{
foreach (string arg in args)
{
writer.WriteLine(arg);
}
}

I remember some in the group said, Linq will replace (most of it)
foreach. How can achive what i am doing above with linq?

You could use Linq in the following way:

args.Aggregate(new StreamWriter("log.log"),
(writer, arg) => { writer.WriteLine(args); return writer; },
writer => { writer.Dispose(); return true; });

But you would lose resources (a FileStream included in StreamWriter) if
WriteLine throws an exception.

But my sample would do fine with a StringBuilder:
args.Aggregate(new StringBuilder(),
(sb, arg) => sb.AppendLine(args),
sb => sb.ToString());
 
and on the whole this is
obviously an inferior solution (as there's no need to convert an
IEnumerable to List just to iterate over it).

On account that you don't know me I will ignore the fact that you are
telling me something so obvious :-)

Peter, I've no doubt that it is very obvious to you; my reply was
mainly meant for the person who originally started the thread, but
also to anyone else who might stumble onto this thread googling an
answer to the same question. In my experience, people often tend to
take the first working solution that they can find, without bothering
to understand what it actually does, and what are the implications. I
don't see that ever changing, so the only way to help on the global
scale is to ensure that as many as of those quick answers as possible
are accurate.
I disagree with this.  IEnumerable.ForEach would merely do the same as a
foreach anyway, so there would be absolutely no difference; it's merely a
matter of taste.  I think the lack of IEnumerable.ForEach is an annoyance.

I think (just a wild guess, but still) that the reason why there's no
ForEach is that it is useful only for the side effects provided by the
lambda, while the general LINQ pattern seems to be about freedom from
side-effects (all other LINQ methods are usually used with side-effect
free lambdas). In that sense, not providing ForEach could be some way
of drawing a line between the functional and the imperative world,
similar to Haskell's do-notation. Want to use LINQ? Stick to
functional and pure. Need side-effects? You have to use a statement,
rather than an expression, for that!

Me, I'd prefer to have enforced explicit [Pure] declarations (and full-
fledged macros...) - but that's another story.
 
Back
Top