範囲/枠(FromとTo)データを分割/統合するベースとなるアルゴリズム
Start(S)列とEnd(E)列で昇順にソートしておくと、
データの並び順は以下の4パターンに分類されます。
pattern1(start is same value)
S1■■■■■■■■■■E1
S2■■■■■■■■■■□□□□□□□□□□□E2
pattern2
S1■■■■■■■■■■■■■■■■■■E1
□□□□□□□S2■■■■■■■■■■■■■■■■■■■■■■■E2
pattern3(END is same value)
S1■■■■■■■■■■■■■■■■■■E1
□□□□□□□S2■■■■■■■■■■■E2
pattern4(all same)
S1■■■■■■■■■■■■■■■■■■E1
S2■■■■■■■■■■■■■■■■■■E2
''' <summary> ''' 例)呼び出し方 ''' </summary> Private Sub ExecSplitAndConsolidateRangeData() ' Init Class Dim clsCTRL As New ClsSplitAndConsolidateRangeData() ' DataTable Dim datTable As New DataTable ' Create Initial DataTable clsCTRL.InitializeDataTable(datTable) ' データ作成 For Each s As String In Me.RichTextBox1.Lines Dim rwNew As DataRow = datTable.NewRow Dim sItems() As String = s.Split(",") rwNew(0) = sItems(0) rwNew(1) = sItems(1) datTable.Rows.Add(rwNew) Next ' 変換されたデータが0件になるまで続ける Dim result As Double = 1 While (result > 0) ' 呼出し result = clsCTRL.SplitAndConsolidateRangeData(datTable) End While ' データをセット Me.DataGridView1.DataSource = datTable End Sub
★ここからがデータを整合性を保ちながら分割・統合するクラス
''' <summary> ''' 範囲(From~To,Start~End...etc)からなるデータを統合、分割する方法 ''' </summary> Public Class ClsSplitAndConsolidateRangeData ' 変数宣言エリア Public Const S As String = "S" '開始 Public Const E As String = "E" '終了 Public Const FORMAT As String = "000000" Public Const DATA As String = "DATA" 'データエリア Public Const DEL As String = "DEL" ' 削除対象フラグ ' クラス内テーブル Public TBL_MAIN As New DataTable() ''' <summary> ''' 削除対象フラグ ''' </summary> Enum DELFLAG DEL NONE End Enum ''' <summary> ''' データテーブルを初期化する ''' </summary> ''' <param name="DATA_TABLE"></param> Public Sub InitializeDataTable(ByRef DATA_TABLE As DataTable) Try DATA_TABLE = New DataTable() DATA_TABLE.Columns.Add(S, Type.GetType("System.String")) DATA_TABLE.Columns.Add(E, Type.GetType("System.String")) DATA_TABLE.Columns.Add(DATA, Type.GetType("System.String")) DATA_TABLE.Columns.Add(DEL, Type.GetType("System.String")) Catch ex As Exception End Try End Sub ''' <summary> ''' 実処理(分割、統合) ''' </summary> ''' <param name="TBL_TARGET"></param> Public Function SplitAndConsolidateRangeData(ByRef TBL_TARGET As DataTable) As Double ' 何件更新したか?0件になるまで再帰呼出し Dim dblResult As Double = 0 Try ' インデックス:カレント行 Dim idx As Double ' インデックス:最大行 Dim idxMax As Double = TBL_TARGET.Rows.Count - 2 'SORT TBL_TARGET = SortDataTable(TBL_TARGET, S & " Asc, " & E & " Asc ") 'DELETE DeleteRowData(TBL_TARGET) 'ChangeAccept TBL_TARGET.AcceptChanges() ' 現在行と次の行を比較していく For idx = 0 To idxMax ' 元データ格納 Dim _S1 As String ' 開始1 Dim _E1 As String ' 終了1 Dim _S2 As String ' 開始2 Dim _E2 As String ' 終了3 Dim _S3 As String ' 開始new Dim _E3 As String ' 終了new ' 加工済みデータ格納用 Dim E1 As String ' 終了1 Dim S2 As String ' 開始2 Dim S3 As String ' 開始new Dim E3 As String ' 終了new '現在行を取得 _S1 = TBL_TARGET.Rows(idx).Item(S).ToString() _E1 = TBL_TARGET.Rows(idx).Item(E).ToString() '次の行を取得 _S2 = TBL_TARGET.Rows(idx + 1).Item(S).ToString() _E2 = TBL_TARGET.Rows(idx + 1).Item(E).ToString() '新しく作成される行 _S3 = "" _E3 = "" ' 重複範囲がある場合は分割/統合対象 If (_S1 <= _S2) And (_S2 <= _E1) Then ' 影響を受けたデータをカウント dblResult = dblResult + 1 ' データの成形 S3 = _S2 E3 = _E1 E1 = (CDbl(_S2) - 1).ToString(FORMAT) S2 = (CDbl(_E1) + 1).ToString(FORMAT) TBL_TARGET.Rows(idx).Item(E) = E1 TBL_TARGET.Rows(idx + 1).Item(S) = S2 '新規Row作成 Dim rwNEW As DataRow rwNEW = TBL_TARGET.NewRow() rwNEW.Item(S) = S3 'または、_S2でもOK rwNEW.Item(E) = E3 'または、_E1でもOK ' データカラムがある場合(DATA1,DATA2が影響を受けない) rwNEW.Item(DATA) = TBL_TARGET.Rows(idx).Item(DATA) & TBL_TARGET.Rows(idx + 1).Item(DATA) 'データの整合性チェック(削除フラグを設定する) CheckDataValue(TBL_TARGET.Rows(idx)) CheckDataValue(TBL_TARGET.Rows(idx + 1)) CheckDataValue(rwNEW) 'とりあえず追加してしまう(Rows.Addメソッドだと必ず最後尾に追加) TBL_TARGET.Rows.Add(rwNEW) End If Next Catch ex As Exception Finally TBL_TARGET.AcceptChanges() End Try Return dblResult End Function ''' <summary> ''' テーブルをソートする ''' DataTable自体にはソートをしてくれる機能がありませんが、DataTable.Select を応用することでソート処理ができます。 ''' </summary> ''' <param name="tblTarget"></param> ''' <param name="sortText">"Age DESC , ID ASC"</param> ''' <returns></returns> Public Function SortDataTable(ByVal tblTarget As DataTable, ByVal sortText As String) As DataTable 'ソート後の DataTable を用意 Dim dtblSrt As New DataTable() Try 'ソート前テーブルの情報をクローン dtblSrt = tblTarget.Clone() 'DataTable.Select()を使いソート(第二引数にソート条件を書く) Dim rows As DataRow() = tblTarget.Select(Nothing, sortText).Clone() 'ソートされてる DataRow 配列をソート後の DataTable に追加 For Each row As DataRow In rows dtblSrt.ImportRow(row) Next Catch ex As Exception End Try Return dtblSrt End Function ''' <summary> ''' 削除フラグを設定する ''' </summary> ''' <param name="rwTarget"></param> Private Sub CheckDataValue(ByRef rwTarget As DataRow) Try ' 開始>終了は不整合データで削除 If rwTarget.Item(S).ToString() > rwTarget.Item(E).ToString() Then rwTarget.Item(DEL) = CDbl(DELFLAG.DEL) End If Catch ex As Exception End Try End Sub ''' <summary> ''' 実際にテーブルから削除する ''' </summary> ''' <param name="DEL_TABLE"></param> Private Sub DeleteRowData(ByRef DEL_TABLE As DataTable) For Each rwDEL As DataRow In DEL_TABLE.Rows ' 実際に削除 If rwDEL.Item(DEL).ToString() = CStr(CDbl(DELFLAG.DEL)) Then rwDEL.Delete() End If Next DEL_TABLE.AcceptChanges() End Sub End Class