如何省略选择lambda中的值

本文关键字:lambda 何省略 选择 | 更新日期: 2023-09-27 18:01:24

我想做一个简单的CSV解析器。它应该遍历一个逗号分隔的值列表,并将它们放在IList<int>中。这些值应该是整数。如果一个值是不可解析的,我只想忽略它。

这是我到目前为止的代码:

csv.Split(',').Select(item =>
{
    int parsed;
    if (int.TryParse(item, out parsed))
    {
        return parsed;
    }
    continue; //is not allowed here
}).ToList();

然而,这里(当然)不允许使用continue如何省略一个值在我的选择实现?

注意:我当然可以使用foreach或LINQ表达式,但我想知道如何使用lambda。

如何省略选择lambda中的值

如何:

public static IEnumerable<int> ExtractInt32(this IEnumerable<string> values) {
    foreach(var s in values) {
        int i;
        if(int.TryParse(s, out i)) yield return i;
    }
}

:

var vals = csv.Split(',').ExtractInt32().ToList();

这里的优点:

  • 避免魔幻的"哨兵"数字(如int.MinValue)
  • 避免了一个单独的和断开连接的"it is valid"/"parse"步骤(所以没有重复)

Select转换值。它不会过滤。Where正在这样做:

csv.Split(',')
   .Select(item =>
           {
               int parsed;
               return new { IsNumber = int.TryParse(item, out parsed), 
                            Value = parsed };
           })
   .Where(x => x.IsNumber)
   .Select(x => x.Value);

另外,请参考下面这个聪明而简短的答案。请注意,这里"聪明"的意思并不完全是肯定的。

一种方法是返回一些默认值,然后跳过它。

errorInt = int.MinValue;
csv.Split(',').Select(item =>
{
    int parsed;
    if (int.TryParse(item, out parsed))
    {
        return parsed;
    }
    else
    {
        return errorInt;
    }
}).Where(val => val != errorInt).ToList();

我认为你有三个选择:

  1. 请使用SelectMany,它将允许您以空可枚举对象返回您希望省略的元素(或者长度为1的可枚举对象)。
  2. 使用一个你确定不会在集合中出现的int值(例如-1)来表示"省略",然后将它们过滤掉。这种方法是脆弱的,因为您可能会选择一个随后出现在集合中的值,这将导致一个微妙的错误。(你可以通过使用更大的数据类型来缓解这个问题,例如long并选择int范围之外的值,但随后你将需要转换回int。)
  3. 使用Nullable<int> (int?)代替,然后过滤掉null的值。

1:

csv.Split(',').SelectMany(item =>
    {
        int parsed;
        if (int.TryParse(item, out parsed))
        {
            return new[] {parsed};
        }
        return Enumerable.Empty<int>();   
    }
3:

csv.Split(',').Select(item =>
    {
        int parsed;
        if (int.TryParse(item, out parsed))
        {
            return (int?) parsed;
        }
        return (int?) null;
     }
    .Where(item => item.HasValue)
    .Select(item => item.Value);

try this:

int dummy;
sv.Split(',').Where(c => int.TryParse(c,out dummy)).Select(c => int.Parse(c));

int.TryParse(..)只是检查它是否是一个要转换为int型的有效字符串。out参数被忽略——我们不再需要它。

我们知道,只有那些"符合"Select()的字符串值才可以安全地解析为int值。

为什么不在数组上使用Where,然后只选择合适的整数

csv.Split(',')
    .Where(item => 
          { 
              int parsed; 
              return int.TryParse(item, out parsed); 
          })
    .Select(item => Convert.ToInt32(item));

我可能会直接使用:

csv.Split(',').Where(item => isValid(item)).Select(item => TransformationExpression(item));

csv.Split(',').Select(item => ReturnsDummyValueIfInvalid(item)).Where(item => item != DummyValue);
int TempInt;
List<int> StuffIWant = csv.Split(',').Where(item => int.TryParse(item, TempInt)).ToList();