私はこのような値のExcelシートを持っています:
R1:A 1 0 1 1 0 1
R2:B 0 0 1 1 0 0
R3:C 1 0 1 1 0 1
R4:D 1 0 1 1 0 1
R5:E 0 0 1 1 00R
列出力:
A、C、D(一致する列があるため)
B、E
一致する値に基づいて列をグループ化するVBAスクリプトが必要です。これを大量のデータセット(たとえば417列)とn行で実行する必要があります。もっと一般化してください。手伝ってください。よろしくお願いします。
クリスは絶対に正しいです。「私のすべての問題を解決してください」のような質問は、ここでは受け入れられません。
あなたは VBA をほとんど、またはまったく知らず、この問題をどこから始めればよいか分からないと思います。お気に入りの検索エンジンに「Excel VBA チュートリアル」と入力すると、チュートリアルの選択肢が表示されます。いくつか試してみて、一番気に入ったものを選び、体系的に取り組んでください。驚くほど早く理解を深めることができます。
ただし、最初に、問題に関するチュートリアルを作成します。個々のステートメントについては、VB ヘルプや検索エンジンで簡単に調べることができるので、あまり説明しません。たとえば、最初のステートメントはOption Explicit
. 検索エンジンに「excel vba option explicit」と入力すると、このステートメントの機能と、それを含めることをお勧めする理由を説明するページが表示されます。
Excel の開き方、VB エディターの開き方、モジュールの作成方法、マクロの実行方法を知っていることを前提としています。そうでない場合、これらはインターネット上のチュートリアルで最初に説明されることになります.
ワークシートInputでワークブックを作成しました。入力に次のデータをロードしました。
行 2 から 6 はデータと一致します。ヘッダー行と、長さの異なるいくつかのデータ行を追加しました。あなたは一般化された解決策を求めていますが、どのように一般化されているかわかりません。これは、あなたが求めているよりも多かれ少なかれかもしれません. 同様のワークシートを作成するか、要件に合わせて以下のコードを変更してください。
次のマクロTest1を VB モジュールにコピーして実行します。
Option Explicit
Sub Test1()
Dim ColMax As Long
Dim RowMax As Long
With Worksheets("Input")
' There are many different ways of identifying the last used row and
' column. SpecialCells has a selection of parameters and is worth
' knowing so I have decided to use it to identify the last row and
' column.
ColMax = .Cells.SpecialCells(xlCellTypeLastCell).Column
RowMax = .Cells.SpecialCells(xlCellTypeLastCell).Row
' Debug.Print outputs values to the Immediate Window which will be at the
' bottom of the VB Editor window. If the Immediate Window is is missing,
' click Ctrl+G.
Debug.Print "Last used column " & ColMax
Debug.Print "Last used row " & RowMax
End With
End Sub
私のデータでは、マクロは次をイミディエイト ウィンドウに出力します。
Last used column 10
Last used row 13
列「J」は10列目です。このコードは、最後に使用された行と列を識別し、マクロが正しい数の行と列を調べるかどうかを知る必要があります。イミディエイト ウィンドウに値を出力すると、コードを簡単にチェックできます。
次に、マクロTest2をモジュールに追加して実行します。
Sub Test2()
Dim ColCrnt As Long
Dim ColMax As Long
With Worksheets("Input")
ColMax = .Cells.SpecialCells(xlCellTypeLastCell).Column
Debug.Print "Row 1:"
For ColCrnt = 1 To ColMax
Debug.Print "Col " & ColCrnt & "=" & .Cells(1, ColCrnt).Value & " ";
If ColCrnt Mod 5 = 0 Then
Debug.Print
End If
Next
End With
End Sub
私のデータでは、マクロは次をイミディエイト ウィンドウに出力します。
Row 1:
Col 1=Id Col 2=Value 1 Col 3=Value 2 Col 4=Value 3 Col 5=Value 4
Col 6=Value 5 Col 7=Value 6 Col 8=Value 7 Col 9=Value 8 Col 10=Value 9
VB ヘルプまたはインターネットを使用して、私が使用したステートメントの説明を取得することを期待していますが、私が何をしているのかについての説明が必要です。
検討:
ColMax = Worksheets("Input").Cells.SpecialCells(xlCellTypeLastCell).Column
マクロTest2ではWorksheets("Input")
、文字列の残りの部分をWith Statement
. これにより、コードはより速く、より明確に、より小さくなりますが、ここのように単一の文字列を書くこともできました。
Worksheets("Input")
ワークシート全体を参照します。
Worksheets("Input").X
ワークシートのパート X を参照します。グラフやデフォルト値を参照することもできましたが、セルを参照したかったのです。 Worksheets("Input").Cells
ワークシート内のすべてのセルを参照します。
Worksheets("Input").Cells.X
セルの一部、またはセルを操作するメソッドを参照します。 Worksheets("Input").Cells.Sort
たとえば、ワークシートを並べ替えることができます。
Worksheets("Input").Cells.SpecialCells
に関する情報を返す一連のメソッドの 1 つにアクセスできますWorksheets("Input").Cells
。与えるパラメーターの追加:Worksheets("Input").Cells.SpecialCells(xlCellTypeLastCell)
必要なメソッドを示します。
最後に、.Column
必要なプロパティを特定するために追加します。
VBA やほとんどすべての最新のプログラミング言語を理解するには、このドット表記法を理解することが不可欠です。ではX.Y
、Y は X の一部、X に適用されるメソッド、または X のプロパティにすることができます。
Worksheets("Input").Cells(R, C)
行 R と列 C の単一セルにアクセスできます。R は最小値 1 の整数で、最大値は使用している Excel のバージョンによって異なります。 Rows.Count
使用しているバージョンの最大行数を示します。C は、整数 (5 など) または列コード (「E」など) にすることができます。列「A」は列 1 です。
Debug.Print Expression
Expressionをイミディエイト ウィンドウに 出力し、その後に改行を続けます。Expressionをイミディエイト ウィンドウにDebug.Print Expression;
出力しますが、その後に改行を追加しません。
ColCrnt Mod 5
ColCrnt の余りを 5 で割った値を返します。この余りが 0 であることをテストすることで、5 行ごとに改行を追加できます。
for ループを使用して、行 1 のすべての値を出力しました。
マクロTest2には 14 個のステートメントしか含まれていませんが、多くの VBA 概念が使用されています。ゆっくりと取り組んでください。F8 キーを使用してマクロ ステートメントを 1 つずつ実行し、各ステートメントの機能を調べます。このマクロを理解できれば、問題を解決するために知っておく必要があるほとんどすべてのことを知っていることになります。
ここで、一致する行について考える必要があります。より複雑な VBA が必要になるため、行の照合に効率的なアルゴリズムは使用しません。知識が蓄積されたら、後でコードを強化できます。私が使用するアプローチは次のとおりです。
一致を記録するには、行 2、4、および 5 が同じであることを記録する何らかの方法が必要ですが、さらに行 3、6、および 8 が同じであることを発見します。行 4 と行 2 を一致させたので、行 4 と行 5 をチェックしたくありません。
ブール配列を使用して 2 番目の要件を満たします。
Dim Matched() As Boolean
ReDim Matched(2 To RowMax)
For RowMast = 2 to RowMax
Matched(RowMast) = False
Next
ではDim Matched() As Boolean
、()
動的配列が必要だと言っています。動的配列は、実行時に上限と下限を変更できる配列です。VBA は、動的配列を使用できる数少ない言語の 1 つであり、下限を設定できる数少ない言語の 1 つです。
ReDim Matched(2 To RowMax)
下限を 2 (= 最初のデータ行) として指定し、上限を RowMax (= 最後のデータ行) として指定します。ReDim Matched(N)
which が N 個のエントリが必要であり、使用されている場合は Option Base ステートメントに従って下限を決定するようにコンパイラに任せるなどのステートメントをよく目にします。Option Base ステートメントを追加または変更することによって誰かが私の配列に干渉したくないので、私は常に下限を指定します。
以下は、Matched のすべての要素を False に設定します。最近のほとんどの言語は変数を初期化するため、これは必要ありません。そうではなかったときのことを覚えており、明示することを好みます。
For RowMast = 2 to RowMax
Matched(RowMast) = False
Next
P > N > M の場合、行 N と行 P を行 M と照合するとき、Matched(N) と Matched(P) を True に設定して、行 N を後の行に対してテストしないようにします。
試合を記録する方法はたくさんあります。文字列を構築するという大雑把なテクニックを使用します。
マクロTest3は、シークの出力を作成します。これは効率的なコードではありませんが、最小限の VBA で機能します。このマクロをモジュールに追加して実行します。イミディエイト ウィンドウへの出力は、追加した余分な行を除いて、要求した出力です。
A, C, D
B, E, G
F, J
I, L
VBAプログラミングで頑張ってください。
Sub Test3()
Dim ColCrnt As Long
Dim ColMax As Long
Dim MatchCrnt As Boolean
Dim Matched() As Boolean
Dim MatchStgTotal As String
Dim MatchStgCrnt As String
Dim RowMast As Long ' The master row; the row I am comparing
' against later rows
Dim RowMax As Long
Dim RowSub As Long ' The subordinate row; the row I am comparing
' against an earlier row
With Worksheets("Input")
ColMax = .Cells.SpecialCells(xlCellTypeLastCell).Column
RowMax = .Cells.SpecialCells(xlCellTypeLastCell).Row
MatchStgTotal = "" ' No matches discovered yet
' Initialise Matched
ReDim Matched(2 To RowMax)
For RowMast = 2 To RowMax
Matched(RowMast) = False
Next
For RowMast = 2 To RowMax
If Not Matched(RowMast) Then
' This row has not been matched against an earlier row
MatchStgCrnt = "" ' No matches for row RowMast discovered yet
For RowSub = RowMast + 1 To RowMax
' Match row RowMast against every later row
If Not Matched(RowSub) Then
' This row has not been matched against an earlier row
MatchCrnt = True ' Assume RowSub matches RowMast
' until find otherewise
For ColCrnt = ColMax To 2 Step -1
' Compare cells from right to left so rows with different
' numbers of values fails to match quickly. This is the only
' consession to efficiency in this loop. There are much better
' ways of doing this but I think I have included enough VBA in
' this tutorial.
If .Cells(RowMast, ColCrnt).Value <> _
.Cells(RowSub, ColCrnt).Value Then
' These rows do not match
MatchCrnt = False
Exit For ' N point checking further cells
End If
Next
If MatchCrnt Then
' Row RowSub matches RowMast
' Add this row's Id to the list of matches against RowMast
MatchStgCrnt = MatchStgCrnt & ", " & .Cells(RowSub, 1).Value
Matched(RowSub) = True ' Do not check this row again
End If
End If
Next RowSub
If MatchStgCrnt <> "" Then
' RowMast has been matched against one or more other rows.
' MatchCrnt contains a list of those other rows.
If MatchStgTotal <> "" Then
' A previous row have been matched.
' Terminate it's string with a newline
MatchStgTotal = MatchStgTotal & vbLf
End If
MatchStgTotal = _
MatchStgTotal & .Cells(RowMast, 1).Value & MatchStgCrnt
End If
End If
' Note: Matched(RowMast) has not been set if row RowMast has been matched
' because I will never loook as row RowMast again.
Next RowMast
End With
Debug.Print MatchStgTotal
End Sub