3

我想做一个简单的 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。

4

8 回答 8

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

这里的好东西:

  • 避免神奇的“前哨”数字(如int.MinValue
  • 避免了单独且断开连接的“它是有效的”/“解析”步骤(因此没有重复)
于 2013-02-26T12:04:08.387 回答
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);

此外,请参阅此答案以获取一种聪明而简短的方法。请注意,“聪明”的含义在这里并不完全是肯定的。

于 2013-02-26T12:03:24.087 回答
1

One way is to return some default value and then skip it.

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();
于 2013-02-26T12:04:54.623 回答
1

Why not to use Where on array and only then select proper ints

csv.Split(',')
    .Where(item => 
          { 
              int parsed; 
              return int.TryParse(item, out parsed); 
          })
    .Select(item => Convert.ToInt32(item));
于 2013-02-26T12:05:44.910 回答
1

我认为你有三个选择:

  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);
于 2013-02-26T12:03:35.377 回答
1

尝试这个:

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

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

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

于 2013-02-26T12:08:35.047 回答
0
int TempInt;
List<int> StuffIWant = csv.Split(',').Where(item => int.TryParse(item, TempInt)).ToList();
于 2013-02-26T12:05:31.183 回答
0

我可能只会使用:

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

或者,

csv.Split(',').Select(item => ReturnsDummyValueIfInvalid(item)).Where(item => item != DummyValue);
于 2013-02-26T12:03:37.037 回答