Sub Duplicate_Delete(ByVal ORIGIN_SHEET_NAME As String, ByRef hairetsu() As String, ByVal rngTaishoColumn As Integer)
Dim myDic As Object, myKey As Variant
Dim c As Variant, vardata As Variant
Dim lp As Integer
Dim Maxrow As Long
Set myDic = CreateObject("Scripting.Dictionary")
With Worksheets(ORIGIN_SHEET_NAME)
Maxrow = .Cells(Rows.Count, rngTaishoColumn).End(xlUp).Row
vardata = .Range(.Cells(2, rngTaishoColumn), .Cells(Maxrow, rngTaishoColumn)).Value
End With
For Each c In vardata
If Not c = Empty Then
If Not myDic.Exists(c) Then
myDic.Add c, Null
End If
End If
Next
lp = 0
myKey = myDic.Keys
ReDim hairetsu(lp)
For i = 0 To myDic.Count - 1
If myKey(i) <> "*" Then
hairetsu(lp) = myKey(i)
lp = lp + 1
If i <> myDic.Count - 1 Then
ReDim Preserve hairetsu(lp)
End If
End If
Next i
Set myDic = Nothing
1Option Explicit
23' 処理実行メインモジュールです
4Sub Main()
56 ' 変数宣言
7 Dim datas As Variant
8 Dim sheet As Worksheet
9 Dim filterdData() As Variant
10 Dim columnItemsA As Collection
11 Dim columnItemA As Variant
12 Dim columnItemsB As Collection
13 Dim columnItemB As Variant
14 Dim columnItemsC As Collection
15 Dim columnItemC As Variant
16 Dim columnItemsD As Collection
17 Dim columnItemD As Variant
1819 ' 処理を実行するシートを取得します
20 Set sheet = ThisWorkbook.Worksheets("処理対象シート")
2122 ' 全セルの値を取得します (但し1行目は空行のため2行目から取得します)
23 datas = readData(sheet, "A2")
2425 ' 重複を排除したA列~D列の値を取得
26 Set columnItemsA = removeDuplication(getColumnData(datas, 1))
27 Set columnItemsB = removeDuplication(getColumnData(datas, 2))
28 Set columnItemsC = removeDuplication(getColumnData(datas, 3))
29 Set columnItemsD = removeDuplication(getColumnData(datas, 4))
3031 ' 全ての値のパターンごとに行を抽出して合計値 (便宜的に5行目に数字が記載されていると仮定) を計算します
32 For Each columnItemA In columnItemsA
33 For Each columnItemB In columnItemsB
34 For Each columnItemC In columnItemsC
35 For Each columnItemD In columnItemsD
36 filterdData = filterData(datas, columnItemA, columnItemB, columnItemC, columnItemD)
37 Debug.Print (columnItemA & ", " & columnItemB & ", " & columnItemC & ", " & columnItemD & " = " & sumData(filterdData, 5))
38 Next
39 Next
40 Next
41 Next
4243End Sub
4445' 指定列の数字を全て足した結果を返却します
46' 数字以外が混じっていた場合はVBAのエラーが発生します
47Private Function sumData(filterdData() As Variant, columnNumber As Long) As Long
4849 ' 変数宣言
50 Dim i As Long
51 Dim sum As Long
5253 ' 全ての数字を足します
54 sum = 0
55 If IsEmptyArray(filterdData) Then
56 sumData = sum
57 Exit Function
58 End If
59 For i = LBound(filterdData) To UBound(filterdData)
60 sum = sum + CLng(filterdData(i, columnNumber))
61 Next
62 sumData = sum
6364End Function
6566' ワークシートのデータをフィルターした結果を返却します。
67' フィルター結果が存在はなかった場合は 空の配列 を返却します
68' 第1引数 : ワークシートのデータ
69' 第3引数 : 列ごとのフィルター定義リスト (フィルター不要な列については * を指定すること)
70Private Function filterData(ByRef datas As Variant, ParamArray filterWords() As Variant) As Variant()
7172 ' 変数宣言
73 Dim i As Long
74 Dim j As Long
75 Dim k As Variant
76 Dim filterWordIndex As Long
77 Dim filterWordMaxIndex As Long
78 Dim numOfcolumn As Long
79 Dim result() As Variant
80 Dim isValidData As Boolean
81 Dim isMatchedRowNumbers As Collection
8283 ' オブジェクトを初期化
84 Set isMatchedRowNumbers = New Collection
8586 ' データの行数を取得します
87 numOfcolumn = UBound(datas, 2) - LBound(datas, 2) + 1
8889 ' フィルター定義リストの最大indexを取得します
90 filterWordMaxIndex = UBound(filterWords)
9192 ' 全行走査
93 For i = LBound(datas, 1) To UBound(datas, 1)
9495 ' 処理対象行
96 isValidData = True
97 filterWordIndex = -1
98 For j = LBound(datas, 2) To UBound(datas, 2)
99 filterWordIndex = filterWordIndex + 1
100 If filterWordMaxIndex >= filterWordIndex Then
101 If filterWords(filterWordIndex) <> "*" And CStr(datas(i, j)) <> filterWords(filterWordIndex) Then
102 isValidData = False
103 Exit For
104 End If
105 End If
106 Next
107108 ' フィルター条件に合致する行を記憶します
109 If isValidData Then
110 isMatchedRowNumbers.Add i
111 End If
112113 Next
114115 ' 合致する結果がない場合は Empty を返却します
116 If isMatchedRowNumbers.Count = 0 Then
117 ReDim result(0, 0)
118 filterData = result
119 Exit Function
120 End If
121122 ' 結果を配列に設定します
123 i = 0
124 ReDim result(1 To isMatchedRowNumbers.Count, LBound(datas, 2) To UBound(datas, 2))
125 For Each k In isMatchedRowNumbers
126 i = i + 1
127 For j = LBound(datas, 2) To UBound(datas, 2)
128 result(i, j) = datas(k, j)
129 Next
130 Next
131132 ' 結果返却
133 filterData = result
134135End Function
136137' 二次元配列から特定の列のデータのみ取得します
138' 第2引数は、例えばA列の場合は 1 を指定します
139Private Function getColumnData(ByRef data As Variant, ByRef columnNumber As Long) As Collection
140141 ' 変数宣言
142 Dim i As Long
143 Dim result As Collection
144145 ' 結果初期化
146 Set result = New Collection
147148 ' 全行走査して指定された列のデータを Collection に設定します
149 For i = LBound(data, 1) To UBound(data, 1)
150 result.Add data(i, columnNumber)
151 Next
152153 ' 結果返却
154 Set getColumnData = result
155156End Function
157158' 処理を実施するワークシートの文字を読み取ります
159Private Function readData(ByRef targetSheet As Worksheet, Optional ByRef startFrom As String = "A1") As Variant
160161 ' 使用済みの全てのセルの値を取得します
162 With targetSheet
163 readData = .Range(.Range(startFrom), getLastCell(targetSheet))
164 End With
165166End Function
167168' 配列が空であるかを判定します
169Private Function IsEmptyArray(data() As Variant) As Boolean
170171On Error GoTo ERROR
172173 ' 配列のサイズを確認します
174 If (0 < UBound(data, 1)) Then
175 IsEmptyArray = False
176 Else
177 IsEmptyArray = True
178 End If
179 Exit Function
180181ERROR:
182183 'エラーが発生した場合は空の配列とみなします
184 IsEmptyArray = True
185186End Function
187188' シートで使用されている最も右下のセルを取得します
189Private Function getLastCell(ByRef sheet As Worksheet) As Range
190 With sheet.UsedRange
191 Set getLastCell = .Cells(.Cells.Count)
192 End With
193End Function
194195' Collection型から重複を排除します
196Private Function removeDuplication(ByRef items As Collection) As Collection
197198 ' 変数宣言
199 Dim dic As Scripting.Dictionary
200 Dim result As Collection
201 Dim item As Variant
202203 ' オブジェクトを初期化します
204 Set dic = New Scripting.Dictionary
205 Set result = New Collection
206207 ' Collectionから重複を排除します
208 For Each item In items
209 If Not dic.Exists(CStr(item)) Then
210 dic.Add CStr(item), ""
211 result.Add CStr(item)
212 End If
213 Next
214215 ' 結果返却
216 Set removeDuplication = result
217218End Function
219220' Collectionの中身を標準出力します (デバック用の関数です)
221Private Sub showCollectionItems(ByRef items As Collection, Optional ByRef title As String = "")
222 Dim item As Variant
223 If title <> "" Then
224 Debug.Print title
225 End If
226 For Each item In items
227 Debug.Print CStr(item)
228 Next
229End Sub
230