Reputation: 553
Ciao everyone, i was finally able to switch from .NET Framework 2.0 to .NET Framework 4.0.
I am trying to get some experience about lambda expression and LINQ.
Is it possible to translate this:
for (int cont = 0;cont < args.Length; cont++)
Console.WriteLine("#" + cont + " " + "<" + args + ">");
into a single line lambda expression,or using LINQ, or even some other costruct i am no aware of ? Thank you in advance.
Upvotes: 1
Views: 405
Reputation: 111940
LINQ operations shouldn't have side effects or do actions. They should only be used to produce, from a IEnumerable<T>
another IEnumerable<T>
(or from a IQueryable<T>
another IQueryable<T>
or IEnumerable<T>
) (or if aggregating, like .Max
, .All
... a single result)
Read for example http://blogs.msdn.com/b/ericlippert/archive/2009/05/18/foreach-vs-foreach.aspx.
(and note that this question is quite asked on SO... Read for example my reply here ToList().ForEach in Linq and see a solution to a similar problem)
Now, if you hate yourself enough, you can do this:
strs.Select((p, index) =>
{
Console.WriteLine("#" + index + " " + "<" + p + ">");
return true;
}).All(p => p);
We are using the .All(p => p)
to "materialize" the Select
operation. This because Select
is "lazy" and won't be executed if no one cycles it.
Technically you could even try to obfuscate it a little:
strs.Select((p, index) =>
{
Console.WriteLine("#" + index + " " + "<" + p + ">");
return false;
}).Any(p => p);
(All
checks that all the elements are true
and stops if one of the is false
, so it has to cycle all of them (because we always return true;
). Any
(as written) checks that at least one of the elements is true
and then stops (but all of our elements are false
, becasue we do return false;
so the Any
will cycle all the elements)
Now... The advantage of these techniques over using ToList
is that we aren't "duplicating" an Array
to a List<T>
just to use a "wrong" method of List<T>
. If the ForEach
method of List<T>
is "wrong", duplicating an Array
to a List
just to use it is doubly-wrong.
Upvotes: 6
Reputation: 36995
There's something you must understand first. LINQ is a functional style API. It's main purpose is to provide an easy and concise way to manipulate sequences.
Your code could be written using LINQ, but it's not desirable: writing stuff to a stream (such as a console) is best done in imperative style, and your request smacks of golden hammer.
Upvotes: 4
Reputation: 117175
This will do exactly what you've asked for:
args
.Select((x, n) => String.Format("#{0} <{1}>", n, args))
.ToList()
.ForEach(Console.WriteLine);
It produces the same as your code:
#0 <System.String[]>
#1 <System.String[]>
#2 <System.String[]>
I'm guessing you wanted something more like this:
var args = new [] { "Apple", "Banana", "Cherry", };
args
.Select((x, n) => String.Format("#{0} <{1}>", n, x))
.ToList()
.ForEach(Console.WriteLine);
Which produces:
#0 <Apple>
#1 <Banana>
#2 <Cherry>
Upvotes: 1
Reputation: 108880
Converting it to a lambda expression is trivial, and useless.
Action doLoop = ()=>{for (int cont = 0;cont < args.Length; cont++)
Console.WriteLine("#" + cont + " " + "<" + args + ">");}
But if you want to replace the loop with linq, that's possible but a bad idea. Linq is designed for side effectless code, Console.WriteLine
is a side effect.
If you want to use linq, but still keep the Console.WriteLine
call you could write:
foreach(string s in Enumerable.Range(0,args.Length).Select("#" + cont + " " + "<" + args + ">"))
Console.WriteLine(s);
It would be possible to abuse Select
to entirely eliminate the loop, but that's too ugly to post here.
Many people have defined a ForEach
extension method with which the code becomes:
Enumerable.Range(0,args.Count).ForEach(()=>Console.WriteLine("#" + cont + " " + "<" + args + ">"));
But I'm not fond of this style.
Upvotes: 1
Reputation: 1631
I hope this links will help you to understand and learn Lambdas and Linq.
Upvotes: 1
Reputation: 52501
I don't know why you would want this but:
args.ToList().ForEach(i => Console.WriteLine("#{0} <{1}>",
args.ToList().IndexOf(i),
i));
I suppose you did want to output the item itself and not the whole list on every line.
And I've made the construction of the output somewhat nicer.
IMO: Your original code is faster and easier to read.
Upvotes: 3
Reputation: 4902
your args must be an array:
Array.ForEach(args, s => { Console.WriteLine("#" + Array.IndexOf(args, s) + " " + "<" + args + ">"); });
Upvotes: -1
Reputation: 57593
Assuming something like this:
string[] args = new string[] { "a", "pippo", "c" };
you can try this:
args.ToList().ForEach(
p => Console.WriteLine(
String.Format("# {0} <{1}>", p, args.Length)));
Upvotes: 0