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は(もちろん)許可されていません。select実装で値を省略する方法は?

注:もちろん、foreachまたはLINQ式を使用することはできますが、ラムダを使用してそれを行う方法を考えています。

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

これを試して:

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

ちょうどそれint.TryParse(..)がintに変換される有効な文字列であるかどうかをチェックします。outパラメータは無視されます-私たちはそれを必要としません。

に「makes-it」する文字列値のみがSelect()、intとして安全に解析できる値であることがわかっています。

于 2013-02-26T12:08:35.047 に答える
1

3つの選択肢があると思います。

  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

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

Where配列で使用せず、適切なintを選択するのはなぜですか

csv.Split(',')
    .Where(item => 
          { 
              int parsed; 
              return int.TryParse(item, out parsed); 
          })
    .Select(item => Convert.ToInt32(item));
于 2013-02-26T12:05:44.910 に答える
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 に答える
0
int TempInt;
List<int> StuffIWant = csv.Split(',').Where(item => int.TryParse(item, TempInt)).ToList();
于 2013-02-26T12:05:31.183 に答える