質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
86.12%
CSV

CSV(Comma-Separated Values)はコンマで区切られた明白なテキスト値のリストです。もしくは、そのフォーマットでひとつ以上のリストを含むファイルを指します。

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Visual Studio

Microsoft Visual StudioはMicrosoftによる統合開発環境(IDE)です。多種多様なプログラミング言語に対応しています。

解決済

DataTable 指定した列の値によって行ごとに抽出する列を変更する

YaMaKaWa
YaMaKaWa

総合スコア1

CSV

CSV(Comma-Separated Values)はコンマで区切られた明白なテキスト値のリストです。もしくは、そのフォーマットでひとつ以上のリストを含むファイルを指します。

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Visual Studio

Microsoft Visual StudioはMicrosoftによる統合開発環境(IDE)です。多種多様なプログラミング言語に対応しています。

2回答

0グッド

1クリップ

474閲覧

投稿2022/12/07 16:28

質問内容

C#で、csvファイルを読み込みDataTableとして取得し、そこから特定の列を抽出しDataGridViewへ出力するアプリを作成しました。
そこから列を抽出する際、指定した列の値によって抽出する列を行ごとに変更したいのですが、この部分が上手くいきません。解決法がありましたら回答宜しくお願いします。

読み込むcsvファイル(サンプル)と該当ソースコード

csv

1F1,F2,F3,F4,F5,F6,F7,F8,F9,F10,F11,F12,F13,F14,F15, 2============================== 310,05,01,11,03,01,80,10,09, , , , , , , 410,10,01,03,01,02,95,10,05, , , , , , , 510,15,02,02,00,03,04,02,00,15,15,00, , , , 610,20,02,02,06,02,10,01,03,16,20,04, , , , 710,25,03,01,03,01,04,00,01,05,00,01,18,20,02, 810,30,03,15,02,02,07,02,02,31,02,02,24,25,01,

一番上の行はカラム名となります。
このcsvファイルを読み込み、下記ソースコードで特定の列を抽出しDataGridViewへ出力します。

C#

1DataTable dt = new DataTable(); 2 3private void button_Click(object sender, EventArgs e) //DataTableから指定した列を取得 4 { 5 //一行ずつ読み込み 6 foreach(DataRow dr in dt.Rows) 7 { 8 DataView dview = new DataView(dt); 9 //抽出する列を指定 10 dt = dview.ToTable(false, new string[5] { "F1", "F2", "F3", "F4", "F5" }); 11 12 Console.WriteLine(dr); 13 } 14 //DataGridViewに出力 15 dataGridView1.DataSource = dt; 16 }

この抽出する列を、カラム名【F3】の値によって個別に変えていきたいというのをやりたいです。
今回の場合、カラム名【F3】が「01」の行は【F1~F5】を、「02」の行は【F1~F5、F7、F8】、「03」の行は【F1~F5、F7、F8、F10、F11】をそれぞれ個別に抽出したいです。

試したこと

当初の考えとしては、foreachループ文で一行ずつ出力するときにswitch文で抽出する列を分岐させるといった方法で行けると思ったのですが、これではうまくいきませんでした。

C#

1DataTable dt = new DataTable(); 2 3private void button_Click(object sender, EventArgs e) //DataTableから指定した列を取得 4 { 5 var stringArr = dt.Rows[0].ItemArray.Select(x => x.ToString()).ToArray(); 6 7 //一行ずつ読み込み 8 foreach(DataRow dr in dt.Rows) 9 { 10 switch(dr["F3"].ToString()) //F3の数値で分岐 11 { 12 case "01": 13 dt = dtview.ToTable(false, new string[5] { "F1", "F2", "F3", "F4", "F5" }); 14 break; 15 case "02": 16 dt = dtview.ToTable(false, new string[7] { "F1", "F2", "F3", "F4", "F5", "F7", "F8" }); 17 break; 18 case "03": 19 dt = dtview.ToTable(false, new string[9] { "F1", "F2", "F3", "F4", "F5", "F7", "F8", "F10", "F11" }); 20 break; 21 } 22 Console.WriteLine(dr); 23 } 24 dataGridView1.DataSource = dt; 25 }

補足情報

・Visual Studio 2022
・Windows フォームアプリケーション(.Net Framework) C#

以下のような質問にはグッドを送りましょう

  • 質問内容が明確
  • 自分も答えを知りたい
  • 質問者以外のユーザにも役立つ

グッドが多くついた質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

気になる質問をクリップする

クリップした質問は、後からいつでもマイページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

下記のような質問は推奨されていません。

  • 間違っている
  • 質問になっていない投稿
  • スパムや攻撃的な表現を用いた投稿

適切な質問に修正を依頼しましょう。

KOZ6.0

2022/12/07 18:27

最初のコードはループする意味がありません。 「DataView.ToTable(Boolean, String[])」 https://learn.microsoft.com/ja-jp/dotnet/api/system.data.dataview.totable?view=netframework-4.8#system-data-dataview-totable(system-boolean-system-string()) を熟読しましょう。 また、DataTable は DefaultView を持っているので 新しく DataView を作る必要もありません。 「DataTable.DefaultView プロパティ」 https://learn.microsoft.com/ja-jp/dotnet/api/system.data.datatable.defaultview?view=netframework-4.8 後のコードについては、新しく DataTable を作ってデータを格納すると良いと思います。
SurferOnWww

2022/12/07 23:33

以下のようにできればいいのですか? 違ったらどこがどのように違うか教えて下さい。 Form 上に一つだけ配置してある DataGridView に CSV ファイルのデータを全行 (質問のサンプルで言うと 6 行) 表示したい。但し表示するのは F11 列まで、さらに F3 列の値が 01 の場合 F5 列までで残りの列は空白、02 の場合 F8 列までで残りの列は空白、03 の場合 F11 列までとする。
YaMaKaWa

2022/12/08 12:44

仰る通りです。
SurferOnWww

2022/12/08 15:05

ならば CSV ファイルを読んできて DataTable を作成する際そのような内容にすれば良いと思うのですが?
SurferOnWww

2022/12/09 14:06

質問者さん、回答したのでフィードバックを返してください。役に立った/立たなかったぐらいはすぐに返せるのでは? 役に立たなかったならどこがダメかを書くとより期待に近い回答が出てくるかも。
YaMaKaWa

2022/12/12 12:13

すみません、この土日が色々忙しく、回答を見ることも試すこともできませんでした。 遅れてしまいましたが、回答ありがとうございます。お陰で助かりました。

回答2

0

ベストアンサー

やりたいことは、

Form 上に一つだけ配置してある DataGridView に CSV ファイルのデータを全行 (質問のサンプルで言うと 6 行) 表示したい。但し表示するのは F6 と F9 を除く F11 列まで。さらに F3 列の値が 01 の場合 F5 列までで残りの列は空白、02 の場合 F8 列までで残りの列は空白、03 の場合 F11 列までとする。

・・・と理解して回答します。

CSV ファイルを読んできて 表示しない列 F6, F9, F12 ~ F15 を削除し、F3 の値によって表示しない列の値は "" として DataTable を作成し、それをそのまま DataGridView に表示する案を書いておきます。(先に DataTable を作ってそれを加工するのではなく)

コードは以下の通りです。デザイン画面でツールボックスから DataGridView を Form にドラッグ&ドロップしています。

C#

1using Microsoft.VisualBasic.FileIO; 2using System; 3using System.Collections.Generic; 4using System.Data; 5using System.Linq; 6using System.Text; 7using System.Windows.Forms; 8 9namespace WindowsFormsApp1 10{ 11 public partial class Form14 : Form 12 { 13 public Form14() 14 { 15 InitializeComponent(); 16 } 17 18 private void Form14_Load(object sender, EventArgs e) 19 { 20 var filepath = @"CSV ファイルのパス"; 21 var encoding = new UTF8Encoding(); 22 var table = CreateDataTable(filepath, encoding); 23 this.dataGridView1.AutoSizeColumnsMode = 24 DataGridViewAutoSizeColumnsMode.AllCells; 25 this.dataGridView1.DataSource = table; 26 } 27 28 private DataTable CreateDataTable(string path, Encoding encoding) 29 { 30 // TextFieldParser は Microsoft が提供している Visual 31 // Basic .NET 用のクラスライブラリ。C# のアプリでも 32 // Microsoft.VisualBasic.dll を参照に追加すれば利用可 33 using (var tfp = new TextFieldParser(path, encoding)) 34 { 35 //フィールドがデリミタで区切られている 36 tfp.TextFieldType = FieldType.Delimited; 37 38 // デリミタを , とする 39 tfp.Delimiters = new string[] { "," }; 40 41 // フィールドを " で囲み、フィールド内に改行文字、 42 // デリミタを含めることができるか 43 tfp.HasFieldsEnclosedInQuotes = true; 44 45 // 空白文字をトリム 46 tfp.TrimWhiteSpace = true; 47 48 // CSV ファイルは 1 行目がヘッダ 49 string[] header = tfp.ReadFields(); 50 51 // 表示しない列を削除。CSV の各行の最後が , なので "F15" の後 52 // に余計な列 "" ができてしまう。それも要削除 53 header = header.Except(new string[] { 54 "F6", "F9", "F12", "F13", "F14", "F15", ""}).ToArray(); 55 56 DataTable dt = new DataTable(); 57 DataRow dr; 58 DataColumn dc; 59 60 // DataTable の列の設定 61 for (int i = 0; i < header.Length; i++) 62 { 63 dc = new DataColumn(header[i], typeof(string)); 64 dt.Columns.Add(dc); 65 } 66 67 // CSV のデータから DataRow を作り DataTable に追加 68 while (!tfp.EndOfData) 69 { 70 string[] fields = tfp.ReadFields(); 71 72 // 特定のインデックスの要素を削除するため List<string> 型を使う 73 List<string> fieldList = fields.ToList(); 74 // F12 以降を削除 75 fieldList.RemoveRange(11, fieldList.Count - 11); 76 // F9 を削除 77 fieldList.RemoveAt(8); 78 // F6 を削除 79 fieldList.RemoveAt(5); 80 81 // F3 が "01" なら F7 以降を "" に書き換え 82 if (fieldList[2] == "01") 83 { 84 for (int i = 5; i < fieldList.Count; i++) 85 { 86 fieldList[i] = ""; 87 } 88 } 89 90 // F3 が "02" なら F10 以降を "" に書き換え 91 if (fieldList[2] == "02") 92 { 93 for (int i = 7; i < fieldList.Count; i++) 94 { 95 fieldList[i] = ""; 96 } 97 } 98 99 dr = dt.NewRow(); 100 for (int i = 0; i < fieldList.Count; i++) 101 { 102 dr[header[i]] = fieldList[i]; 103 } 104 dt.Rows.Add(dr); 105 } 106 107 return dt; 108 } 109 } 110 } 111}

結果は:

イメージ説明

投稿2022/12/09 03:33

編集2022/12/09 03:48
SurferOnWww

総合スコア17344

良いと思った回答にはグッドを送りましょう。
グッドが多くついた回答ほどページの上位に表示されるので、他の人が素晴らしい回答を見つけやすくなります。

下記のような回答は推奨されていません。

  • 間違っている回答
  • 質問の回答になっていない投稿
  • スパムや攻撃的な表現を用いた投稿

このような回答には修正を依頼しましょう。

回答へのコメント

YaMaKaWa

2022/12/12 12:09

回答ありがとうございます。 試してみたら丁度上手い具合にやりたいことと合致しました。

0

今回の場合、カラム名【F3】が「01」の行は【F1~F5】を、「02」の行は【F1~F5、F7、F8】、「03」の行は【F1~F5、F7、F8、F10、F11】をそれぞれ個別に抽出したいです。

いろいろ方法はあるでしょうが、全体を読んだDataTableを編集する方向でやりました。

cs

1using System; 2using System.Data; 3using System.Globalization; 4using System.IO; 5using System.Linq; 6using System.Windows.Forms; 7using CsvHelper; 8using CsvHelper.Configuration; 9 10 11namespace Q29bnkqsbv7swf1 12{ 13 public partial class Form1 : Form 14 { 15 public Form1() 16 { 17 InitializeComponent(); 18 var dataGridView = new DataGridView 19 { 20 Parent = this, 21 Dock = DockStyle.Fill, 22 AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.AllCells, 23 AutoSizeRowsMode = DataGridViewAutoSizeRowsMode.AllCells, 24 ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.AutoSize, 25 RowHeadersWidthSizeMode = DataGridViewRowHeadersWidthSizeMode.AutoSizeToAllHeaders, 26 }; 27 28 29 Dummy("test.csv"); // テスト用csv作成 30 var dt = GetDataTable("test.csv"); // csvをそのままDataTableに読んだとして 31 32 foreach (DataRow row in dt.Rows) 33 { 34 object[] array; 35 switch (row["F3"]) 36 { 37 case "01": array = row.ItemArray.Take(5).ToArray(); break; 38 case "02": array = row.ItemArray.Take(8).ToArray(); break; 39 case "03": array = row.ItemArray.Take(11).ToArray(); break; 40 default: array = row.ItemArray; break; // 123以外が来たときどうすべきか 41 } 42 43 // いったん行をすべて空にする 44 row.ItemArray = Enumerable.Repeat(DBNull.Value, dt.Columns.Count).ToArray(); 45 row.ItemArray = array; // 詰めなおし 46 } 47 48 // いらない列を削除 49 foreach (var col in new[] { "F6", "F9", "F12", "F13", "F14", "F15", "Column1", }) 50 { 51 dt.Columns.Remove(col); 52 } 53 54 dataGridView.DataSource = dt; 55 } 56 57 58 private static void Dummy(string path) 59 { 60 var s = @" 61F1,F2,F3,F4,F5,F6,F7,F8,F9,F10,F11,F12,F13,F14,F15, 62============================== 6310,05,01,11,03,01,80,10,09, , , , , , , 6410,10,01,03,01,02,95,10,05, , , , , , , 6510,15,02,02,00,03,04,02,00,15,15,00, , , , 6610,20,02,02,06,02,10,01,03,16,20,04, , , , 6710,25,03,01,03,01,04,00,01,05,00,01,18,20,02, 6810,30,03,15,02,02,07,02,02,31,02,02,24,25,01, 69".Trim(); 70 File.WriteAllText(path, s); 71 } 72 73 // 何らかの方法でcsvをDataTableに 74 private static DataTable GetDataTable(string path) 75 { 76 var config = new CsvConfiguration(CultureInfo.InvariantCulture) 77 { 78 ShouldSkipRecord = (args) => args.Row[0].StartsWith("="), 79 }; 80 81 using (var streamReader = new StreamReader(path)) 82 using (var csvReader = new CsvReader(streamReader, config)) 83 using (var dataReader = new CsvDataReader(csvReader)) 84 { 85 var dataTable = new DataTable(); 86 dataTable.Load(dataReader); 87 foreach (DataColumn col in dataTable.Columns) col.ReadOnly = false; 88 89 return dataTable; 90 } 91 } 92 } 93}

NuGet Gallery | CsvHelper 30.0.1

アプリ画像

投稿2022/12/08 22:55

編集2022/12/09 23:49
TN8001

総合スコア8046

良いと思った回答にはグッドを送りましょう。
グッドが多くついた回答ほどページの上位に表示されるので、他の人が素晴らしい回答を見つけやすくなります。

下記のような回答は推奨されていません。

  • 間違っている回答
  • 質問の回答になっていない投稿
  • スパムや攻撃的な表現を用いた投稿

このような回答には修正を依頼しましょう。

回答へのコメント

YaMaKaWa

2022/12/12 12:11

回答ありがとうございます。 試したところコチラが質問した通りの結果が出力されました。

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
86.12%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問

同じタグがついた質問を見る

CSV

CSV(Comma-Separated Values)はコンマで区切られた明白なテキスト値のリストです。もしくは、そのフォーマットでひとつ以上のリストを含むファイルを指します。

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Visual Studio

Microsoft Visual StudioはMicrosoftによる統合開発環境(IDE)です。多種多様なプログラミング言語に対応しています。