標題:
比對兩直欄的數值刪除重複橫列問題
[打印本頁]
作者:
greetingsfromtw
時間:
2016-10-16 22:58
標題:
比對兩直欄的數值刪除重複橫列問題
(檔案連結:)
各位前輩好,
小弟遇到一個問題,
本想試著使用字典物件,
但因所想比對的兩欄數值(K欄與M欄)欄位有可能會其中一欄空白,
另一欄非空白,
在這樣的情形下若是因空白而刪除,
恐怕會刪到不該刪的資料,
之前有比照板上前輩提供的程式碼去修改後做出一個檔案,
應該是板上沒錯,但不知該如何用搜索功能查詢自己的回文(非帖子),
以後使用前輩程式碼實在應該加註解附上原出處才是,
請見諒,小弟以後一定注意.
目前這個檔案還是有些問題,
有時明明兩欄皆為空白,但該橫列仍未被刪除;
第二點就是C欄必須非空白,
但不知該如何做修改.
還有一點就是不知何故,
明明重複的資料,還是無法徹底刪除,
這點也令小弟相當不解,
少量資料測試時沒有太大問題,
但大量資料就會出現問題.
先將小弟所期望的程式碼規則詳述如下以供參考:
(第一橫列為欄位名稱,不做比對.
資料共計15欄位,K欄與M欄為想要比對的數值,
兩欄數值無關連,不互相比對,僅自行比對)
1.若兩個或多個橫列的欄位K數值相同(或空白),且欄位M數值也相同(或空白),
則只留下一橫列,其餘刪除.
2.若兩個或多個橫列的欄位K數值相同,但欄位M的數值不同,
則這些橫列不變動.
在這些橫列中,留下一欄位的K數值,其餘橫列的欄位M清除.
欄位M的數值與位置不變動.
3.與上述規則相似,
若兩個或多個橫列的欄位K數值不同,但欄位M數值相同,
則這些橫列不變動.
欄位K的數值與位置不變動.
留下一欄位M數值,其餘橫列的欄位L數值清除.
4.若橫列的欄位K跟欄位M均為空白,
則刪除此橫列.
5.欄位K的數值與欄位M的數值不互相比較,兩欄數值各自比對,沒有關聯.
6.欄位K及欄位M的數值均為正整數或空白,不會是0或其他值.
附上小弟參考前輩程式碼修改後的程式及附檔如下:
附檔下載(Google雲端硬碟)
Public Sub extwo()
Dim ar()
Range("c2").Resize(Cells(Rows.Count, 3).End(xlUp).Row, 1).Select
Selection.Resize(Selection.Rows.Count - 1, 1).Select
Selection.Copy Range("a2")
arr = Range("A2:AD" & Cells(Rows.Count, 1).End(xlUp).Row)
K = UBound(arr)
For i = 1 To UBound(arr) - 1
For j = i + 1 To UBound(arr)
If arr(i, 1) = "" Or arr(j, 1) = "" Then GoTo 10
If arr(i, 11) & arr(i, 13) = arr(j, 11) & arr(j, 13) Then
For L = 1 To UBound(arr, 2)
arr(j, L) = ""
Next
K = K - 1
ElseIf arr(i, 11) = arr(j, 11) And arr(i, 13) <> arr(j, 13) Then
If arr(i, 13) = "" Then
arr(i, 11) = ""
Else
arr(j, 11) = ""
End If
ElseIf arr(i, 11) <> arr(j, 11) And arr(i, 13) = arr(j, 13) Then
If arr(i, 11) = "" Then
arr(i, 13) = ""
Else
arr(j, 13) = ""
End If
ElseIf arr(i, 11) = "" And arr(i, 13) = "" Then
arr(i, 1) = ""
ElseIf arr(j, 11) = "" And arr(j, 13) = "" Then
arr(j, 1) = ""
'
End If
10:
Next
Next
ReDim ar(1 To K, 1 To UBound(arr, 2))
K = 1
For i = 1 To UBound(arr)
If arr(i, 1) <> "" Then
For L = 1 To UBound(arr, 2)
ar(K, L) = arr(i, L)
Next
K = K + 1
End If
Next
Range("a2:AD" & Cells(Rows.Count, 1).End(xlUp).Row).Clear
[a2].Resize(UBound(ar), UBound(arr, 2)) = ar
Columns(1).ClearContents
[L2].Select
End Sub
複製代碼
可以的話,
希望能夠有前輩不吝指點小弟,十分感謝.
作者:
GBKEE
時間:
2016-10-17 09:18
回復
1#
greetingsfromtw
試試看 是這樣媽?
Option Explicit
Sub Ex()
Dim D As Object, Rng As Range, i As Long, St As String
Set D = CreateObject("SCRIPTING.DICTIONARY")
Set Rng = Range("B:P").Rows
For i = 2 To Rng.Rows.Count
If Application.CountA(Rng(1).Rows(i)) = 0 Then Exit For
With Rng.Rows(i)
St = Trim(.Cells(10)) & Trim(.Cells(12))
'**第二點就是C欄必須非空白
If .Cells(2) <> "" And St <> "" Then
If D.EXISTS(St) = False Then D(St) = Rng.Rows(i).Value
'1.若兩個或多個橫列的欄位K數值相同(或空白),且欄位M數值也相同(或空白),
'2.若兩個或多個橫列的欄位K數值相同,但欄位M的數值不同,
End If
End With
Next
If D.Count > 0 Then
Rng(1).Offset(, Rng.Columns.Count + 2).Resize(D.Count, Rng.Columns.Count).Value _
= Application.Transpose(Application.Transpose(D.ITEMS))
End If
End Sub
複製代碼
作者:
greetingsfromtw
時間:
2016-10-17 13:23
本帖最後由 greetingsfromtw 於 2016-10-17 13:25 編輯
回復
2#
GBKEE
非常感謝GBKEE前輩無私提供程式碼,
也讓小弟知道字典物件是可以這樣使用的,
小弟今天研究了好一陣子,從中獲益甚多,
照這樣看來,字典物件實在是太強大了,
可用於解決許多棘手問題.
另外值得一提的是,
前輩還費心在程式碼中提供相關註解以利小弟學習研究之用,
這點令人感動,再次感謝前輩.
可以的話請允許小弟斗膽進一步詢問相關問題,
====
1.若兩個或多個橫列的欄位K數值相同,但欄位M的數值不同,
則這些橫列不變動.
在這些橫列中,留下一欄位的K數值,其餘橫列的欄位M清除.
欄位M的數值與位置不變動.
橫列均不刪除.
2.與上述規則相似,
若兩個或多個橫列的欄位K數值不同,但欄位M數值相同,
則這些橫列不變動.
欄位K的數值與位置不變動.
留下一欄位M數值,其餘橫列的欄位K數值清除.
橫列均不刪除.
===
在使用前輩所提供的程式碼時,
若遇上面所述兩點情形,
則會出現問題,這些橫列相同的數值不會被刪除.
也是小弟表達能力不太好,請見諒,有些地方也寫錯,
已略作修改,
以後一定會將問題做更清楚的呈現並檢查過後再提交,造成困擾不好意思.
小弟斗膽,
不知是否能夠麻煩前輩不吝指點迷津,十分感謝.
作者:
greetingsfromtw
時間:
2016-10-17 14:41
回復
2#
GBKEE
感謝前輩提醒,以後發文詢問會直接附上壓縮檔較為直接,文字說明有時不易說明清楚.
附上檔案,請前輩參考:
小弟將檔案說明貼至此以利對照用:
說明:
原始資料橫列2至橫列4的數值2相同,但數值1不同,故數值1不動,數值2保留一個,其餘刪除.
原始資料橫列5至橫列7的數值1相同,但數值2不同,故數值2不動,數值1保留一個,其餘刪除.
原始資料橫列8至10的數值2均相同,數值1空白,故只保留一橫列,其餘兩橫列刪除.保留哪一橫列均可.
原始資料橫列11至13的數值1均相同,數值2空白,故只保留一橫列,其餘兩橫列刪除.保留哪一橫列均可.
原始資料橫列14的數值1及數值2均為空白,故直接刪除此橫列.
還望前輩不吝指點迷津,十分感謝.
作者:
GBKEE
時間:
2016-10-18 05:57
回復
4#
greetingsfromtw
這樣對嗎?
Option Explicit
Sub Ex()
Dim D(1 To 3) As Object, Rng As Range, i As Long, S1 As String, S2 As String, AR
Set D(1) = CreateObject("SCRIPTING.DICTIONARY")
Set D(2) = CreateObject("SCRIPTING.DICTIONARY")
Set D(3) = CreateObject("SCRIPTING.DICTIONARY")
Set Rng = Range("B:P").Rows
For i = 2 To Rng.Rows.Count
If Application.CountA(Rng(1).Rows(i)) = 0 Then Exit For
With Rng.Rows(i)
If .Cells(2) <> "" Then '**第二點就是C欄必須非空白
S1 = .Cells(10)
S2 = .Cells(12)
If Not D(1).EXISTS(S1) And Not D(2).EXISTS(S2) Then
'**字典物件1的Key沒有 數值1 且 字典物件2的Key沒有 數值2
If S1 <> "" And S2 <> "" Then D(3)(S1 & S2) = Rng.Rows(i).Value
D(1)(S1) = ""
D(2)(S2) = ""
ElseIf Not D(1).EXISTS(S1) And D(2).EXISTS(S2) Then
'**字典物件1的Key沒有 數值1 且 字典物件2的Key 有 數值2
AR = Rng.Rows(i).Value
AR(1, 12) = "" '** 不要數值2
D(3)(S1) = AR
ElseIf D(1).EXISTS(S1) And Not D(2).EXISTS(S2) Then
'**字典物件1的Key 有 數值1 且 字典物件2的Key 沒有 數值2
AR = Rng.Rows(i).Value
AR(1, 10) = "" '** 不要數值1
D(3)(S2) = AR
End If
End If
End With
Next
If D(3).Count > 0 Then
Rng(1).Offset(2, Rng.Columns.Count + 2).Resize(D(3).Count, Rng.Columns.Count).Value _
= Application.Transpose(Application.Transpose(D(3).ITEMS))
End If
End Sub
複製代碼
作者:
准提部林
時間:
2016-10-18 10:28
本帖最後由 准提部林 於 2016-10-18 10:32 編輯
2000無法正常開啟附檔(格式太多),
只能猜,無法試解!
作者:
greetingsfromtw
時間:
2016-10-18 12:26
回復
5#
GBKEE
非常感謝GBKEE前輩耐心提供解答,
確實可以完美運作,沒有問題.
真的沒想到字典物件還有如此高深的運用方式,
小弟對VBA的了解實在是太少了,一定努力學習.感謝前輩無私指點.
作者:
greetingsfromtw
時間:
2016-10-18 12:35
回復
6#
准提部林
實在抱歉,小弟當初只顧著傳檔,沒考慮到相容性問題,
以後小弟發問時的附檔會記得改成.xls格式,造成困擾不好意思.
已在此篇附上.xls格式,請前輩參考.
之前也蒙淮提部林前輩指點高深技巧,小弟從中獲益不少,覺得這個討論區不僅高手如雲,而且都願意無私指點像小弟這樣的VBA新手,實在非常感謝.
GBKEE前輩已有提供問題解答,但同一個問題的解答肯定不只一種,若淮提部林前輩願意抽空指點小弟其他解答方式就太好,
再次感謝前輩們的無私指點,
小弟一定努力學習.
[attach]25570[/attach]
作者:
准提部林
時間:
2016-10-18 13:26
回復
8#
greetingsfromtw
還是無法正常開啟檔案(格式太多), 大概猜著寫, 能自行更改最好:
Sub T_TEST()
Dim Arr, i&, j%, xD, TK&, TM&, N&
Arr = Range("A2:AD" & Cells(Rows.Count, 1).End(xlUp).Row)
Set xD = CreateObject("Scripting.Dictionary")
For i = 1 To UBound(Arr)
If Arr(i, 3) = "" Then GoTo 101 'C欄不為空
TK = "k" & Arr(i, 11): TM = "m" & Arr(i, 13) '數字各自冠上不同文字區別
If xD(TK & TM) = 1 Then GoTo 101 '兩欄完全相同且已納入字典, 不處理
If xD(TK) = 1 Then Arr(i, 11) = "": GoTo 999 'K值相同且非第一筆, 清空K值
If xD(TM) = 1 Then Arr(i, 13) = "": GoTo 999 'M值相同且非第一筆, 清空M值
999: N = N + 1
For j = 1 To UBound(Arr, 2): Arr(N, j) = Arr(i, j): Next '取得更新後的資料放在原陣列
xD(TK & TM) = 1: xD(TK) = 1: xD(TM) = 1 '納入字典檔並冠上1為識別碼
101: Next i
If N = 0 Then Exit Sub
[A2:AD2].Resize(UBound(Arr)).Clear '清空原資料
[A2:AD2].Resize(N) = Arr '填入更新資料
End Sub
複製代碼
作者:
greetingsfromtw
時間:
2016-10-18 15:40
回復
9#
准提部林
非常感謝淮提部林前輩無私提供程式碼,小弟大開眼界.
兩位前輩所使用的解題方式都是小弟前所未見,需要一點時間消化.
真的非常感謝.
後來發現該檔案不知何故被告知有一格式存在,怎麼清也清不掉,
另開新檔再把資料重新輸入後即解決問題,
造成前輩困擾,真的很不好意思,下次附檔時一定注意.
小弟冒昧將前輩程式碼略做修改後,確實已解決問題,附上修改後程式碼如下,
再次感謝前輩熱心協助.
字典物件真的是一門高深學問,一定努力學習.
'http://forum.twbts.com/viewthread.php?from=notice&tid=18582
'感謝淮提部林前輩提供原始程式碼
'此版本是從前輩所提供之原始程式碼去進行修改
Sub T_TEST()
Dim Arr, i&, j%, xD, TK, TM, N&
Arr = Range("c2:AD" & Cells(Rows.Count, 3).End(xlUp).Row)
Set xD = CreateObject("Scripting.Dictionary")
For i = 1 To UBound(Arr)
If Arr(i, 1) = "" Then GoTo 101 'C欄不為空
TK = "k" & Arr(i, 9): TM = "m" & Arr(i, 11) '數字各自冠上不同文字區別
If xD(TK & TM) = 1 Then GoTo 101 '兩欄完全相同且已納入字典, 不處理
If xD(TK) = 1 Then Arr(i, 9) = "": GoTo 999 'K值相同且非第一筆, 清空K值
If xD(TM) = 1 Then Arr(i, 11) = "": GoTo 999 'M值相同且非第一筆, 清空M值
999: N = N + 1
For j = 1 To UBound(Arr, 2): Arr(N, j) = Arr(i, j): Next '取得更新後的資料放在原陣列
xD(TK & TM) = 1: xD(TK) = 1: xD(TM) = 1 '納入字典檔並冠上1為識別碼
101: Next i
If N = 0 Then Exit Sub
[c2:AD2].Resize(UBound(Arr)).Clear '清空原資料
[c2:AD2].Resize(N) = Arr '填入更新資料
End Sub
複製代碼
歡迎光臨 麻辣家族討論版版 (http://forum.twbts.com/)