C# CSVファイルの数値データをDoubleのジャグ配列として得る

C#で、ヘッダー行があり、その下に数値データが並んでいるCSVファイルを一括して取り込む。
ヘッダー（複数行可）はStringのジャグ配列に、数値データは、列ごとにDoubleのジャグ配列に入れる。


#開発環境
Visual Studio 2019
Windows 10
C#
.net 5

##ファイル 先頭から指定行スキップして、指定行数取り込み
もしかしたら.toArray()しないほうが、速度、メモリ的に有利なのかもしれないけど、扱いが楽なのでArray化

```CS
string CsvFilePath = "test.csv";
int RowsToSkip = 2;
int Rows = 1000;
string[] Lines = System.IO.File.ReadLines(CsvFilePath)
                                 .Skip(RowsToSkip).Take(Rows).ToArray();
```
##CSV文字列一行を、double配列にする
```CS
double[] CsvString.Split(',')
          .Select(n => double.TryParse(n.Trim(), out double result) ? result : 0)
          .ToArray();
```

##コード一式
```CS
/// <summary>
/// CSV文字列一行を、double配列にする
/// </summary>
/// <param name="CsvString"></param>
/// <returns></returns>
private double[] CsvStringToDoubleArray(string CsvString)
{
    return CsvString.Split(',').Select(n => double.TryParse(n.Trim(), out double result) ? result : 0).ToArray();
}
/// <summary>
/// CSVファイルからデータ読み込み　
/// ヘッダー列と数値データ配列を得る
/// </summary>
/// <param name="CsvFilePath">CSVファイルパス</param>
/// <param name="RowsToSkip">読み込みから飛ばす行数</param>
/// <param name="HeaderRows">ヘッダー行数</param>
/// <param name="HeaderEncode">ヘッダー文字のエンコード</param>
/// <param name="FixedDataRows">読み込みサイズ　データがこれ以下しかない場合0で埋められる</param>
/// <returns></returns
public (string[][] Header, double[][] NumericData) CSVtoDoubleArray
                        (string CsvFilePath, int RowsToSkip = 0, int HeaderRows = 1, string HeaderEncode = "Shift_JIS",int FixedDataRows = 0)
{

    //.net 5以降これがないとShift_JISエンコードが読み込まれない
    Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
    string[] Lines;
    try
    {
        //FixedDataRowsが設定されていなかったら、全行、設定されていた、その行数分取得
        if (FixedDataRows == 0)
            Lines = System.IO.File.ReadLines(CsvFilePath, Encoding.GetEncoding(HeaderEncode)).Skip(RowsToSkip).ToArray();
        else
            Lines = System.IO.File.ReadLines
                (CsvFilePath, Encoding.GetEncoding(HeaderEncode)).Skip(RowsToSkip).Take(HeaderRows + FixedDataRows).ToArray();
    }
    catch (Exception e)
    {
        MessageBox.Show(e.Message);
        return (null, null);
    }
    int DataRows = Lines.Length- HeaderRows;

    //データ列が0以下なら戻す
    if (DataRows <= 0)
        return (null, null);

    string[][] Header = new string[HeaderRows][];

    //ヘッダー行数分読み込み
    for (int i = 0; i < HeaderRows && i < Lines.Length; i++)
        Header[i] = Lines[i].Split(',').Where(x => x != "").Select(x => x.Trim('\"')).ToArray(); //空白列は除外 注 行最後の,を想定　途中に,,があるとずれる

    int DataColumns;
    //ヘッダーがあれば、先頭ヘッダーの列数　なければ先頭データの列数
    if (HeaderRows > 0)
        DataColumns = Header[0].Length;
    else
        DataColumns = CsvStringToDoubleArray(Lines[0]).Length;

    //データ配列確保用行数
    int AllocationDataRows = DataRows;
    if (FixedDataRows != 0)
        AllocationDataRows = FixedDataRows;

    //ヘッダー、指定行数のジャグ配列の領域確保
    double[][] NumericData = new double[DataColumns][];
    for (int Col = 0; Col < DataColumns; Col++)
        NumericData[Col] = new double[AllocationDataRows];

    for (int Row = 0; Row < DataRows && Row < FixedDataRows; Row++)
    {
        var line = CsvStringToDoubleArray(Lines[Row + HeaderRows]);
        for (int Col = 0; Col < DataColumns && Col < line.Length; Col++)
            NumericData[Col][Row] = line[Col];
    }
    return (Header, NumericData);
}
```
##呼び出し例
```CS
var CsvFilePath = "Test.csv";

//6000行読み込み
(string[][] Header, double[][] Data) = CSVtoDoubleArray(CsvFilePath,RowsToSkip:4,FixedDataRows:6000);
```
Header[0]　ヘッダー一行目のstring配列
Header[0][0]　ヘッダー一行目、1列目

Data[0]    データ一列目のdouble配列
Data[0][0] データ一列目の一つ目のデータ