如何省略选择lambda中的值?

时间:2013-02-26 12:00:15

标签: c# linq select lambda

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

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

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

但是,此处不允许使用continue(当然)。 如何在我的select实现中省略一个值?

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

8 个答案:

答案 0 :(得分:9)

怎么样:

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();

这里的好东西:

  • 避免使用魔法“sentinal”号码(例如int.MinValue
  • 避免单独且断开连接的“它是有效的”/“解析”步骤(所以没有重复)

答案 1 :(得分:2)

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);

此外,请参阅this answer这是一个聪明,简短的方法。请注意&#34;聪明&#34;的含义在这里并不完全正面。

答案 2 :(得分:1)

我认为你有三种选择:

  1. 使用SelectMany代替您将允许您为要省略的元素返回空的可枚举(否则将返回长度为1的可枚举)。
  2. 使用您确定不会在集合中的int值(例如-1)来表示“省略”,然后将其过滤掉。这种方法很脆弱,因为您可能会选择随后出现在集合中的值,这将导致细微的错误。 (您可以通过使用更大的数据类型来缓解此问题,例如long并选择int范围之外的值,但随后您需要转换回int。)
  3. 使用Nullable<int>int?)代替,然后过滤掉null值。
  4. 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);
    

答案 3 :(得分:1)

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

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();

答案 4 :(得分:1)

试试这个:

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

int.TryParse(..)只是检查它是否是要转换为int的有效字符串。 out参数只是被忽略了 - 我们需要它。

我们知道只有那些“使它成为”Select()的字符串值才能被安全地解析为int。

答案 5 :(得分:0)

我可能只会使用:

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

,或者

csv.Split(',').Select(item => ReturnsDummyValueIfInvalid(item)).Where(item => item != DummyValue);

答案 6 :(得分:0)

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

答案 7 :(得分:0)

为什么不在数组上使用Where,然后才选择正确的整数

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