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

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

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

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

C#

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

Visual Studio

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

Q&A

解決済

2回答

1950閲覧

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

YaMaKaWa

総合スコア1

CSV

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

C#

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

Visual Studio

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

0グッド

0クリップ

投稿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#

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

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

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 を作ってデータを格納すると良いと思います。
退会済みユーザー

退会済みユーザー

2022/12/07 23:33

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

2022/12/08 12:44

仰る通りです。
退会済みユーザー

退会済みユーザー

2022/12/08 15:05

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

退会済みユーザー

2022/12/09 14:06

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

2022/12/12 12:13

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

回答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
退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

YaMaKaWa

2022/12/12 12:09

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

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

総合スコア9326

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

YaMaKaWa

2022/12/12 12:11

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問