Reputation: 3427
If I have a list of objects that have the properties fruitName
and numFruits
and I want to pluralize the fruitName
where numFruits
is greater than 1, is it possible to do that in a single statement by chaining together Where
and Foreach
?
Something like:
fruitList.Where(fl => fl.numFruits > 1).ForEach(fl => fl.fruitName = fl.fruitName + "s");
I tried the above and it doesn't work. It complains that System.Collections.Generic.IEnumerable doesn't contain a definition for ForEach.
Upvotes: 0
Views: 109
Reputation: 14685
Given that "append an s" doesn't actually give you the correct answer for many fruits, any approach that does that will give you an incorrect answer, no matter how well it does it.
Consider using a lookup table to map singlular to plurals (and vice versa) instead:
using System;
using System.Collections.Generic;
using System.Linq;
public class Test
{
private static Dictionary<string, string> fruitLookup =
new Dictionary<string, string>
{
{"blueberry", "blueberries"},
{"peach", "peaches"},
{"apple", "apples"}
};
public static void Main()
{
var fruitList = new List<string> {"blueberry", "peach", "apple"};
// Here is your one-line conversion:
var plurals = fruitList.Select(f => fruitLookup[f]).ToList();
foreach (var p in plurals)
{
Console.WriteLine(p);
}
}
}
Upvotes: 0
Reputation: 6486
If you really want a one-liner (it will be harder to maintain) and want to keep the original list intact but only modify some of the elements, you'll have to use a full anonymous function. If you need multiple statements (a block of code), you'll need to include the braces and statement-terminating semicolons like below:
fruitList.ForEach(fl => { fl.fruitName = fl.numFruits > 1 ? fl.fruitName + "s" : fl.fruitName; });
This works on the original list (no subset) and does basically the exact same thing a structured foreach
would do.
Upvotes: 2
Reputation: 19203
Typically you want to use foreach
the language construct when possible. Eric Lippert has a blog post going into additional detail as to why.
Loops are good when you are doing modifications as it makes finding those modifications easier.
foreach (var fl in fruitList.Where(fl => fl.numFruits > 1))
{
fl.fruitName = fl.fruitName + "s";
}
Is more straightforward and accomplishes the same task.
Upvotes: 3
Reputation: 5445
There's a good blog post by Eric Lippert on why there is no “ForEach” sequence operator extension method, essentially the reason is:
The first reason is that doing so violates the functional programming principles that all the other sequence operators are based upon. Clearly the sole purpose of a call to this method is to cause side effects. The purpose of an expression is to compute a value, not to cause a side effect. The purpose of a statement is to cause a side effect. The call site of this thing would look an awful lot like an expression (though, admittedly, since the method is void-returning, the expression could only be used in a “statement expression” context.) It does not sit well with me to make the one and only sequence operator that is only useful for its side effects.
If you wanted to do this in a single statement you could use a .Select()
var newFruitList = fruitList.Where(fl => fl.numFruits > 1).Select(fl => fl.fruitName + "s");
Upvotes: 1
Reputation: 1493
You can use the static Array.ForEach method to update the list.
Array.ForEach(fruitList.Where(fl => fl.numFruits > 1).ToArray(), x => { x.fruitName += "s"; });
Upvotes: 0
Reputation: 834
Like @Tim Schmelter suggested, you can use ToList() to convert to a list and then use the ForEach method on the result returned. Although the ToList() might return a shorter list based on the filter, the original objects themselves would be changed and your fruitList will remain unchanged.
fruitList.Where(fl => fl.numFruits > 1).ToList().ForEach(fl => fl.fruitName = fl.fruitName + "s");
// fruitList still has all elements
Upvotes: 0