Using conditional lambda statements with a foreach

2019-06-21 01:24发布

Why Cant I do something like this?

If I have a List<String> myList populated with items, I want to be able to act on each member in a conditional way like so:

myList.ForEach(a => { if (a.Trim().Length == 0) a = "0.0"; })

But this will not compile. Im guessing its something to do with missing a return value?

Im trying to prepare a list of strings for conversion to doubles, and I want the empty items to show '0.0' so I can just convert the whole list in one go.

标签: c# lambda
3条回答
霸刀☆藐视天下
2楼-- · 2019-06-21 01:35

ForEach is not mutable, it doesn't change the data structure in any way.

You can either:

  1. Handle the loop yourself, with an index
  2. Produce a new list, using .Select and .ToList (provided you're using .NET 3.5)

Example of #1:

for (Int32 index = 0; index < myList.Count; index++)
    if (myList[index].Trim().Length == 0)
        myList[index] = "0.0";

With .NET 3.5 and Linq:

myList = (from a in myList
          select (a.Trim().Length == 0) ? "0.0" : a).ToList();

With .NET 3.5, not using the Linq-syntax, but using the Linq-code:

myList = myList.Select(a => (a.Trim().Length == 0) ? "0.0" : a).ToList();

Edit: If you want to produce a new list of doubles, you can also do that in one go using Linq:

List<Double> myDoubleList =
    (from a in myList
     select (a.Trim().Length == 0 ? "0" : a) into d
     select Double.Parse(d)).ToList();

Note that using "0.0" instead of just "0" relies on the decimal point being the full stop character. On my system it isn't, so I replaced it with just "0", but a more appropriate way would be to change the call to Double.Parse to take an explicit numeric formatting, like this:

List<Double> myDoubleList =
    (from a in myList
     select (a.Trim().Length == 0 ? "0.0" : a) into d
     select Double.Parse(d, CultureInfo.InvariantCulture)).ToList();
查看更多
叼着烟拽天下
3楼-- · 2019-06-21 01:37

@daniel-earwicker's MutateEach Extension solution is a good solution.


Though, for returning a new List, you have the option to use List.ConvertAll<TTo>(Converter<TFrom,TTo>(Func<TFrom, TTo>)), which has been around since .NET 2.0.

It is not Linq, or Lambda.

List<String> nodeStringList = new List<String>(new String[] { "", "0.5 ", " 1.1"}); 

nodeStringList = nodeStringList.ConvertAll<String>((c) => (c.Value.Trim().Length != 0) ? c.Value.Trim() : "0.0");

MSDN Reference - List.ConvertAll

查看更多
地球回转人心会变
4楼-- · 2019-06-21 01:51

What you possibly want is:

public static void MutateEach(this IList<T> list, Func<T, T> mutator)
{
    int count = list.Count;
    for (int n = 0; n < count; n++)
        list[n] = mutator(list[n]);
}

Which would allow:

myList.MutateEach(a => (a.Trim().Length == 0) ? "0.0" : a);

Just put the MutateEach method in a public static class of your own and make sure you have a using directive that will find it.

Whether it's worth defining something like this depends on how often you'd use it. Note that it has to be an extension on IList instead of IEnumerable, so we can perform the updates, which makes it less widely applicable.

查看更多
登录 后发表回答