Duncan_McCloud
Duncan_McCloud

Reputation: 553

Very easy lambda expression

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

Answers (8)

xanatos
xanatos

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

Etienne de Martel
Etienne de Martel

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

Enigmativity
Enigmativity

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

CodesInChaos
CodesInChaos

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

BigL
BigL

Reputation: 1631

I hope this links will help you to understand and learn Lambdas and Linq.

MSDN Lambda Expressions

101 LINQ Examples

Upvotes: 1

GvS
GvS

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

ojlovecd
ojlovecd

Reputation: 4902

your args must be an array:

Array.ForEach(args, s => { Console.WriteLine("#" + Array.IndexOf(args, s) + " " + "<" + args + ">"); });

Upvotes: -1

Marco
Marco

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

Related Questions