13

Is it not allowed to have a conditional operator in a lambda expression in ForEach?

List<string> items = new List<string>{"Item 1", "Item 2", "Item I Care About"};

string whatICareAbout = "";

// doesn't compile :(
items.ForEach(item => item.Contains("I Care About") ? 
whatICareAbout += item + "," : whatICareAbout += "");

Compilation error -> "Only assignment, call, increment, decrement, and new object expressions can be used as a statement"

Trying to use a normal if doesn't work either:

// :(
items.ForEach(item => if (item.Contains("I Care About")) {whatICareAbout += item + ", ";}

Just not possible?

3
  • 2
    Sheesh I am exceptionally impressed with the answers, all within minutes of asking :) I think @SLaks answers the intent of my question, but Aggregate() blows my mind! :) Thanks again everyone :) Commented Nov 29, 2009 at 22:13
  • 1
    You had a string expression as a type of conditional operator, and you needed a statement for your .ForEach() method. That's why compilation error was there. Commented Nov 29, 2009 at 22:41
  • 1
    @Roman - I get it now! I think of a ? x: y as short-hand for if (a) {x} else {y} but ? returns the value of x and y, which was a string in this case... Commented Nov 30, 2009 at 0:12

4 Answers 4

37

You're using the shorter form of lambda expressions, which only allow a single expressions.
You need to the long form, which allows multiple statements.

For example:

items.ForEach(item => {
    if (item.Contains("I Care About")) 
        whatICareAbout += item + ", ";
});
Sign up to request clarification or add additional context in comments.

Comments

6

What are you trying to acheive? Are you trying to form a string of comma separated items where they contain a particular value? In linq you would achieve this using the following:

 List<string> items = new List<string> { "Item 1", "Item 2", "Item I Care About", "Item I Care About", "Item I Care About" }; 
 string whatICareAbout = items.Where(x => x.Contains("I Care About"))
                              .Aggregate( (y, z) => y + ", " + z);

The output from this is "Item I Care About, Item I Care About, Item I Care About".

Note: Aggregate is a great way of ensuring there is no trailing ","

2 Comments

Using Aggregate for sting concat is a very neat idea which I haven't thought of. You could easily change it to use a StringBuilder because StringBuilder has a fluent interface.
hah, I was just adding an Aggregate() code sample to my initial answer... but I like yours better. +1 !
4

The problem was that expression

item.Contains("I Care About") ? whatICareAbout += item + "," : whatICareAbout += ""

is not a statement. It just returns a value which has type string.

There is a trick to make it work (just for fun):

    items.ForEach(item => (item.Contains("I Care About") ?
    whatICareAbout += item + "," : whatICareAbout += "").GetType());

I simply added call to .GetType() method to create a statement from initial expression, and it compiled.

1 Comment

And for .ForEach() you needed a statement :)
1

Try parentheses:

items.ForEach(item => item.Contains("I Care About") ? (whatICareAbout += item + ",") : (whatICareAbout += "") );

+= has a higher precedence than ?, that may be why you're getting the error. With parentheses, the error may go away. Not 100% sure of this, though... lambda expressions may have additional restrictions which prevent use of assignment statements.

UPDATE:

Instead of multiple += statements, it's a lot cleaner to put the conditional on the right-hand side of the assignment, like this:

List<string> items = new List<string> { "one", "two", "three" };
string whatICareAbout = "";
items.ForEach(item => whatICareAbout +=  item.Contains("I Care About") ? (item + ",") : ""); 

UPDATE 2:

But it's even better to just use Aggregate() since it's designed for exactly this scenario. Here's one sample:

string whatICareAbout = items.Aggregate("", (total, item) => item.Contains("I Care About") ? (total + item + ",") : total);

But I think @Matt Breckon's answer above (that I just saw as I was about to post this)is even better than my example since it deals with removing the terminal ",". Look at his answer... :-)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.