ここから本文です

VB.net で CSV 集計と列の入れ替え。

アバター

ID非公開さん

2020/4/918:35:59

VB.net で CSV 集計と列の入れ替え。

Dim ary As New SortedList(Of Index, string)

ary(1) = "0, 10, 20, 30 , 40"
ary(2) = "100, 15, 60, 40 , 70"
ary(3) = ", 45, 80, 17 , "
ary(4) = "1, 33, 22, , 7"

上記のようなデータがあった場合を考えます(空欄は 0 とみなします)。ary(1) から ary(4) までの縦方向の集計を行うと、その答えは(エクセルを使用すれば)

101,103,182,87,117

と得られますが、これを VB.net で実装するには

(1) カンマで区切って更に配列化する
(2) 対応する要素同士で足し算する
(3) 結果を表示する

となるかと思います(『そんなことをしなくてもこっちが早いよ』という御指摘があれば歓迎いたします)。これで終わればいいのですが、

[Q1] 結果を大きいものから並べよ
[Q2] ary(1) から ary(4) も [Q1] の結果に従って対応する要素の順にならべよ

[Q1] の答えは

182,117,103,101,87

ですが、[Q2] はこれに従って並び順を入れ替えて、

ary(1) = "20,40,10,0,30"
ary(2) = "60,70,15,100,40"
ary(3) = "80,,45,,17"
ary(4) = "22,7,33,1,"

となります。

[Q1] はまだしも、[Q2] がさっぱりです。というのも、例は 4 個のデータですが、

<1> データ数は可変(4個以上あるのがほとんど。しかもデータによりまちまち)
<2> データの要素数も可変(上記例を Excel で表示すれば 5 列ですが、これが 6, 7, 8, … 列と増えたり減ったり)

という条件つきです。

Excel を使って手作業で…とはできないので、どうやって VB.net で組んだらよいか困っています。どなたか、良い御知恵を拝借できないでしょうか。

よろしくお願いいたします。

閲覧数:
45
回答数:
3
お礼:
500枚

違反報告

ベストアンサーに選ばれた回答

lar********さん

2020/4/1111:25:01

回答します。

私であれば、DataTableを使用して実現させます。

①CSVデータをDataTableに格納し、縦計を集計
②「①」のデータテーブルを使って、行列を入れ替え
→これをやらないと、DataTableのソートはできません
③「②」の合計を降順にソートし、行列を入れ替え


サンプルソースを作成しましたので、参考にしてみてください。
Imports System.Text
Imports Microsoft.VisualBasic.FileIO

Public Class Form1

Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Const CSV_FILE_PATH As String = "C:\tmp\test.csv"

Dim dt1 As New DataTable
Dim dt2 As New DataTable
Dim dt3 As New DataTable
Dim iCol As Integer = 0

'--------------------------------------------------
' CSVデータをデータテーブルに格納
'--------------------------------------------------
'CSVファイルを開く
Dim tfp As TextFieldParser = New TextFieldParser(CSV_FILE_PATH, Encoding.GetEncoding(932))
tfp.TextFieldType = FieldType.Delimited
tfp.SetDelimiters(",")

'CSVファイルを読み込む
While Not tfp.EndOfData
'1行取得し、カンマ区切りでデータを配列化
Dim sData() As String = tfp.ReadFields()

'データテーブルのカラムが無い場合、作成
If dt1.Columns.Count = 0 Then
For Each sVal As String In sData
dt1.Columns.Add(iCol, Type.GetType("System.Int32"))
iCol += 1
Next
End If

'配列化されたデータを正規化
For iIdx As Integer = 0 To sData.Length - 1
If Trim(sData(iIdx)) = String.Empty Then
sData(iIdx) = "0"
Else
sData(iIdx) = Trim(sData(iIdx))
End If
Next
'データを追加
dt1.Rows.Add(sData)
End While
tfp.Close()

'最終行に縦計を集計し、行を追加
Dim drRow As DataRow = dt1.NewRow
For Each dc As DataColumn In dt1.Columns
drRow(dc.ColumnName) = dt1.Rows.Cast(Of DataRow).Sum(Function(dr) CInt(dr(dc.ColumnName)))
Next
dt1.Rows.Add(drRow)



'--------------------------------------------------
' データテーブルの行列を入れ替えて格納
'--------------------------------------------------
'行数を基に列を追加
For iIdx As Integer = 0 To dt1.Rows.Count - 1
dt2.Columns.Add(iIdx, Type.GetType("System.Int32"))
Next
'列数を基に行を追加
For iIdx As Integer = 0 To dt1.Columns.Count - 1
Dim dr As DataRow = dt2.NewRow
For iIdx2 As Integer = 0 To dt1.Rows.Count - 1
dr.Item(iIdx2) = dt1.Rows(iIdx2).Item(iIdx)
Next
dt2.Rows.Add(dr)
Next



'--------------------------------------------------
' データテーブルの行列を入れ替えて格納
'--------------------------------------------------
'行数を基に列を追加
For iIdx As Integer = 0 To dt2.Rows.Count - 1
dt3.Columns.Add(iIdx, Type.GetType("System.Int32"))
Next
'集計された合計を降順に並び替え
Dim drSort() As DataRow = dt2.Select("", dt2.Columns.Item(dt2.Columns.Count - 1).ColumnName & " DESC")
'列数を基に行を追加
For iIdx As Integer = 0 To dt2.Columns.Count - 1
Dim dr As DataRow = dt3.NewRow
For iIdx2 As Integer = 0 To drSort.Length - 1
dr.Item(iIdx2) = drSort(iIdx2).Item(iIdx)
Next
dt3.Rows.Add(dr)
Next

End Sub

End Class

  • アバター

    質問者

    ID非公開さん

    2020/4/1313:40:00

    御回答ありがとうございます。

    私の実装では(sortedlist も string() もまとめて『配列』と表現します)

    (1) 各要素をカンマで区切って配列にする(ついでに縦方向を集計する)
    (2) (1) の要素を行列と見なして転置行列ならぬ「転置配列」を作る
    (3) 集計値でソートする
    (4) 集計結果を基に、どの要素から並べるべきかを記録する
    (5) 「転置配列」のさらに『転置配列』を作る。この時、(4) の結果を加味しながら行えば集計結果順にソートできている。
    (6) 結果を返す

    これで組むと(作業用配列もたくさん出現する)長々しい「エレファントなコード」になるため『他の人だったらどういう実装をするんだろうか』と思って質問した次第です。DataTable は使ったことがなかったのですが、こちらの方がはるかに「エレガントなコード」ですね。

    是非とも参考にさせていただきます。

返信を取り消しますが
よろしいですか?

  • 取り消す
  • キャンセル

アバター

質問した人からのコメント

2020/4/14 10:41:11

皆様ご回答ありがとうございました。

やはり人が違えばコードも異なるんですね。
これを機会に新しいものにチャレンジしようと思います。

ベストアンサー以外の回答

1〜2件/2件中

並び替え:回答日時の
新しい順
|古い順

プロフィール画像

カテゴリマスター

2020/4/1012:32:47

vb.net or C# では、
CSV読み込みには、いろいろな方法(ライブラリー)があります。
以下ページは、中には古い情報もありますが参考にしてください
https://dobon.net/vb/dotnet/file/readcsvfile.html

任意の行列のCSVデータをそのまま読み込み、
配列やオブジェクトに格納することが可能です

で、データの集計やソート程度ならば
単純に2次元配列かジャグ配列で行列データを管理して
ループで処理しますね

エクセルVBA にはない
vb.net or C# の特徴を生かすなら
ジャグ配列をつかえば、
横方向に対しては、Linq のメソッドが使えます

質問内容については

(1)(2)(3)
はCSV読み込みライブラリーがあります

[Q1]
これは縦方法なので、普通に配列に対してのループ計算です

[Q2]
Q1 の計算結果を配列に格納すれば、あとは、linq で降順ソートできます
https://www.atmarkit.co.jp/fdotnet/dotnettips/880orderby/orderby.ht...

この質問内容の後半の、ary の各要素は並び替えていますが・・・
これはあなたの考え過ぎでは?
CSV配列が正方形が配列であると固定化できるなら
このような考えもできますが

あなた自身が、CSVの行列は不定である可能性を記述していますので
正方形配列には固定されていませんので、そもそも成立していませんよ

返信を取り消しますが
よろしいですか?

  • 取り消す
  • キャンセル

kak********さん

2020/4/922:43:51

こんなモデルを考えてみました。
参考にしてください。

こんなモデルを考えてみました。
参考にしてください。

返信を取り消しますが
よろしいですか?

  • 取り消す
  • キャンセル

この質問につけられたタグ

みんなで作る知恵袋 悩みや疑問、なんでも気軽にきいちゃおう!

Q&Aをキーワードで検索:

Yahoo! JAPANは、回答に記載された内容の信ぴょう性、正確性を保証しておりません。
お客様自身の責任と判断で、ご利用ください。
本文はここまでです このページの先頭へ

「追加する」ボタンを押してください。

閉じる

※知恵コレクションに追加された質問は選択されたID/ニックネームのMy知恵袋で確認できます。

不適切な投稿でないことを報告しました。

閉じる